Wstęp

Celem analizy było zbadanie właściwości materiałów wykorzystywanych w tworzeniu baterii.

Wykorzystane biblioteki

  • skimr - Umożliwia szybkie i przejrzyste generowanie statystyk opisowych dla zbiorów danych, dostarczając podsumowania dostosowane do różnych typów zmiennych.
  • corrplot - Służy do wizualizacji macierzy korelacji.
  • GGally - Rozszerza możliwości ggplot2, umożliwiając tworzenie zaawansowanych wizualizacji, takich jak macierze par wykresów czy korelogramy, co jest przydatne w analizie wielowymiarowej.
  • dplyr - Zapewnia zestaw funkcji do manipulacji danymi w sposób deklaratywny i czytelny, umożliwiając filtrowanie, sortowanie, grupowanie oraz agregowanie danych w ramach złożonych operacji.
  • plotly - Pozwala na tworzenie interaktywnych wykresów.
  • caret - Ułatwia proces budowy modeli predykcyjnych, oferując narzędzia do przygotowania danych, selekcji cech, tuningu hiperparametrów oraz oceny modeli w spójny i zintegrowany sposób.
library(skimr)
library(corrplot)
library(GGally)
library(dplyr)
library(plotly)
library("Hmisc")
library(mlbench)
library(caret)
library(rlang)
library(knitr)
library(DT)
library(dplyr)
library(ggplot2)
library(gridExtra)
library(here)
library(tidyverse)
library(scales)

Jak wyglądają dane?

W celu zilustrowania zawartości zbioru danych, wyświetlono kilka pierwszych wierszy zbioru, aby zaprezentować strukturę tabeli, nazwy zmiennych oraz przykłady wartości, które one przyjmują.

Atrybuty

W poniższej tabeli przedstawiono znajdujące się w zbiorze atrybuty oraz ich definicje.

Atrybut Opis
Battery ID Identyfikator baterii.
Battery Formula Wzór chemiczny materiału baterii.
Working Ion Główny jon, który odpowiada za transport ładunku w baterii.
Formula Charge Wzór chemiczny materiału baterii w stanie naładowanym.
Formula Discharge Wzór chemiczny materiału baterii w stanie rozładowanym.
Max Delta Volume Zmiana objętości w % dla danego kroku napięcia za pomocą wzoru : max(charge, discharge)/min(charge, discharge) -1.
Average Voltage Średnie napięcie dla poszczególnego kroku napięcia.
Gravimetric Capacity Pojemność grawimetryczna, czyli ilość energii na jednostkę masy (mAh/g).
Volumetric Capacity Pojemność wolumetryczna, czyli ilość energii na jednostkę objętości (mAh/cm³).
Gravimetric Energy Gęstość energii w odniesieniu do masy baterii (Wh/kg).
Volumetric Energy Gęstość energii w odniesieniu do objętości baterii (Wh/L).
Atomic Fraction Charge Udział atomowy składników w stanie naładowanym.
Atomic Fraction Discharge Udział atomowy składników w stanie rozładowanym.
Stability Charge Wskaźnik stabilności materiału w stanie naładowanym.
Stability Discharge Wskaźnik stabilności materiału w stanie rozładowanym.
Steps Liczba odrębnych kroków napięcia od pełnego naładowania do rozładowana, oparta na stabilnych stanach pośrednich.
Max Voltage Step Maksymalna bezwzględna różnica między sąsiednimi krokami napięcia.

Charakterystyka zbioru danych

Zbiór danych zawiera 17 atrybutów i 4351 rekordów.

Suma brakujących wartości w zbiorze: 0.

Liczba brakujących wartości w kolumnach
Liczba brakujących wartości
Battery.ID 0
Battery.Formula 0
Working.Ion 0
Formula.Charge 0
Formula.Discharge 0
Max.Delta.Volume 0
Average.Voltage 0
Gravimetric.Capacity 0
Volumetric.Capacity 0
Gravimetric.Energy 0
Volumetric.Energy 0
Atomic.Fraction.Charge 0
Atomic.Fraction.Discharge 0
Stability.Charge 0
Stability.Discharge 0
Steps 0
Max.Voltage.Step 0

Suma duplikatów: 0.

Zbiór danych nie zawiera brakujących wartości ani duplikatów, więc dane nie wymagają czyszczenia.

Zbiór zawiera:
- kolumny znakowe: 2,
- kolumny numeryczne: 11,
- kolumny logiczne: 0

Analiza zbioru danych

W tej części zostanie przeprowadzona analiza wartości atrybutów w zbiorze danych. Celem tej analizy jest zrozumienie rozkładu, zmienności oraz kluczowych cech poszczególnych atrybutów, co pozwoli na lepszą interpretację danych. Analiza obejmie różne metody wizualizacji, takie jak histogramy, wykresy gęstości oraz wykresy pudełkowe, które umożliwią szybkie wychwycenie istotnych trendów, wartości odstających oraz charakterystyki rozkładu danych.

Rozkłady atrybutów

Atrybuty numeryczne

Sekcja obejmuje wizualizację rozkładów wartości dla atrybutów numerycznych. Po lewej stronie znajduje się histogram, który ilustruje częstość występowania różnych wartości atrybutu przyporządkowanych do określonej liczby przedziałów. Pomarańczowy kolor reprezentuje linię gęstości rozkładu (tzw. density plot). Wykres gęstości jest używany do wizualizacji kształtu rozkładu danych, pozwalając na lepsze zrozumienie jego formy w porównaniu do histogramu. Na wykresie znajduje się również czerwona linia pionowa, oznaczająca średnią wartość atrybutu, co pozwala na szybką ocenę jego centralnego położenia.
Po prawej stronie znajduje się wykres pudełkowy (tzw. boxplot), który wizualizuje rozproszenie wartości i pozwala na identyfikację wartości odstających.

Błąd w poleceniu 'Summary.factor(c(1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, ': 
  ‘min’ nie ma sensu dla czynników

Większość rozkładów jest prawoskośna, co oznacza, że większość większość wartości jest mniejszych niż średnia.

  • Max Delta Volume - Dane są wyraźnie skupiene przy zerze, obecne są nieliczne przypadki odstające.
  • Max Voltage Step - Dane są wyraźnie skupiene przy zerze, co sugeruje, że większość danych przyjmuje wartości bliskie zeru. Obecne są nieliczne przypadki odstające.

Główne jony

Tabela przedstawia mediany wartości atryburów numerycznych, dla poszczególnych grup głównego jonu transportującego ładunek (Working Ion).

Na przedstawionym wykresie zaprezentowano rozkład głównych jonów używanych do transportu ładunku w bateriach. Wyraźnie dominuje lit (Li), który występuje znacznie częściej niż inne jony tj. prawie 2500 razy. Sugeruje to powszechne zastosowanie technologii opartych na litowo-jonowych rozwiązaniach, co jest zgodne z ich szerokim wykorzystaniem w przemyśle elektroniki i magazynowania energii. Szczególną zaletą baterii litowo-jonowych jest wysoką gęstość energii. To znaczy, że mogą magazynować dużą ilość energii przy niewielkich rozmiarach i niskiej wadze, co czyni je doskonałym rozwiązaniem dla przenośnych urządzeń, takich jak laptopy i tablety (“Litowo-Jonowe a Litowo-Polimerowe: Szczegółowe Porównanie” 2024). W zestawieniu pierwiastków lit plasuje się na drugim miejscu pod względem grawimetrcznej gęstości energii, zaraz za wapniem.
Pozostałe jony, takie jak wapń (Ca), magnez (Mg), i cynk (Zn), również znajdują zastosowanie, ale w znacznie mniejszym zakresie. Obecność jonów takich jak sód (Na) i potas (K) mogą wskazywać na badania nad alternatywami dla litu, jednak ich zastosowanie jest obecnie ograniczone.


Poniżej znajdują się interkatywne wykresy pudełkowe dla każdej zmiennej numerycznej w zbiorze danych z podziałem na główne jony. Wykresy te umożliwiają eksplorację rozkładu wartości, identyfikację potencjalnych wartości odstających oraz porównanie zmienności w każdej zmiennej dla poszególnych jonów.

Wzory chemiczne materiału baterii

Formula.Charge total
MnO2 49
TiO2 47
VO2 46
CrO2 45
CoO2 43
NiO2 41
FeO2 36
FePO4 26
WO2 25
CoPO4 24
MnP2O7 22
MnPO4 22
VF5 22
CoP2O7 20
FeP2O7 20
V2OF5 20
WO3 20
MoO2 19
V2O5 19
VPO5 18
CrP2O7 17
MnFeCo(PO4)3 17
VP2O7 17

Wykres przedstawia liczbę wystąpień różnych wzorów chemicznych materiałów baterii w stanie naładowanym. W zbiorze jest 2096 różnych wzorów chemicznych materiałów baterii w stanie naładowanym. Najliczniejszymi są MnO2, TiO2, Vo2, CrO2, NiO2, FeO2.


Wykres przedstawia liczbę wystąpień różnych wzorów chemicznych materiałów baterii w stanie rozładowanym. W zbiorze jest 3173 różnych wzorów chemicznych materiałów baterii w stanie rozładowanym. Najczęściej występujące wzory to LiVOF11, Li2O5F5, LiFePO4, LiCoPO4. Znaczna większość najczęściej występujących wzorów zawiera cząsteczkę litu.

Korelacja zmiennych

Poniższa macierz korelacji ilustruje współczynniki korelacji Pearsona dla wybranych atrybutów. Kolory kafelków reprezentują siłę oraz kierunek korelacji. Odcienie niebieskiego wskazują na dodatnią korelację, a odcienie czerwonego na ujemną.

Najwyższy wspolczynnik korelacji wystepuje pomiedzy parami atrybutów:
- Gravimetric Energy i Volumetric Energy - 0.93
- Gravimetric Capcity i Volumetric Capacity - 0.86
- Stability Charge i Stability Discharge - 0.80
- Gravimetric Capacity i Atomic Fraction Discharge - 0.68
- Average Voltage i Gravimetric Energy - 0.67

Korelacja pomiędzy energią grawimetryczną i wolumetryczną

Wykres przedstawia zależność między gęstością energii wolumetryczną (Wh/L, energia na jednostkę objętości) a grawimetryczną (Wh/kg, energia na jednostkę masy), gdzie widoczna jest silna korelacja dodatnia między tymi parametrami. Gęstość energii jest kluczowym wskaźnikiem wydajności baterii - im wyższa wartość, tym więcej energii może być zmagazynowane w danej objętości lub masie baterii, co jest szczególnie istotne w zastosowaniach mobilnych, takich jak pojazdy elektryczne czy urządzenia przenośne. Większość badanych materiałów skupia się w zakresie do 2000 Wh/kg i 7500 Wh/L, choć występuje kilka obiecujących wyjątków o wyższych parametrach, które mogą stanowić potencjalne kierunki rozwoju nowych, wydajniejszych baterii.

Korelacja pomiędzy pojemnością grawimetryczną i wolumetryczną

Wykres przedstawia zależność między pojemnością wolumetryczną (mAh/cm³, ilość ładunku na jednostkę objętości) a grawimetryczną (mAh/g, ilość ładunku na jednostkę masy) materiałów, gdzie pojemność grawimetryczna określa ile energii można zmagazynować w danej masie materiału, a wolumetryczna - ile w danej objętości, co ma kluczowe znaczenie przy projektowaniu baterii o różnym przeznaczeniu. Współczynnik korelacji 0.86 wskazuje na silną zależność między tymi parametrami, choć nie tak silną jak w przypadku gęstości energii. Na przykład, materiał o wysokiej pojemności grawimetrycznej może być lekki, ale zajmować dużo miejsca, podczas gdy materiał o wysokiej pojemności wolumetrycznej może być cięższy, ale bardziej kompaktowy (“Co Warto Wiedzieć o Ogniwach Litowo‑jonowych?” 2024).

Korelacja pomiędzy stabilnością materiału w stanie naładowanym i rozładowanym

Wykres przedstawia zależność między stabilnością materiału w stanie naładowanym (Stability Charge) a stabilnością w stanie rozładowanym (Stability Discharge), ze współczynnikiem korelacji 0.8 wskazującym na silną dodatnią zależność. Stabilność materiału jest kluczowym parametrem określającym, jak dobrze materiał zachowuje swoją strukturę i właściwości podczas cykli ładowania i rozładowania - im niższa wartość, tym materiał jest bardziej stabilny i bezpieczny w użytkowaniu. Większość badanych materiałów skupia się w zakresie niskich wartości (0-2) dla obu parametrów, co jest pożądane, natomiast punkty odstające o wyższych wartościach (powyżej 4) mogą wskazywać na materiały problematyczne, które mogą być mniej odpowiednie do zastosowań w bateriach ze względu na potencjalną niestabilność.

Korelacja pomiędzy pojemnością grawimetryczną i udział atomowym składników w stanie rozładowanym

Wykres przedstawia zależność między pojemnością grawimetryczną (Gravimetric Capacity, mAh/g) a udziałem atomowym w stanie rozładowania (Atomic Fraction Discharge). Można zaobserwować umiarkowanie silną dodatnią zależność, co potwierdza współczynnik korelacji wynoszący 0.68. W miarę wzrostu pojemności grawimetrycznej, udział atomowy w stanie rozładowania zwiększa się, osiągając wartość maksymalną bliską 1.0.
Kolor punktów reprezentuje wartość Atomic Fraction Discharge, gdzie jaśniejsze kolory wskazują na niższe wartości, a ciemniejsze na wyższe. Dane wskazują, że większość obserwacji znajduje się w zakresie niskiej pojemności grawimetrycznej (<1000 mAh/g), a dla wartości powyżej 2000 mAh/g zależność staje się nieliniowa. Sugeruje to, że materiały o wyższej pojemności grawimetrycznej mają tendencję do osiągania wyższych udziałów atomowych w stanie rozładowania.

Korelacja pomiędzy średnim napięciem a energią grawimetryczną

Wykresy przedstawiają zależności między średnim napięciem (Average Voltage, V) a gęstością energii grawimetrycznej (Gravimetric Energy Density, Wh/kg) dla różnych wartości kroku napięcia. Dane wskazują, że wraz ze wzrostem średniego napięcia zwiększa się gęstość energii grawimetrycznej. Większość danych skupia się w zakresie niskich wartości napięcia (<10 V), co sugeruje, że materiały o wyższym napięciu są mniej liczne, ale wykazują większą efektywność energetyczną.

Analiza właściwości

Stabilność w stanie naładowanym i rozładowanym

Stability Charge

  • Określa stabilność materiału w baterii, gdy jest w pełni naładowany
  • Wyższa stabilność oznacza, że materiał będzie mniej podatny na uszkodzenia lub degradację podczas ładowania. Jest to istotne, aby zapewnić długotrwałe działanie baterii bez utraty jej właściwości.

Stability Discharge

  • Określa stabilność materiału w baterii, gdy jest w pełni rozładowany.
  • Stabilność w stanie rozładowanym jest kluczowa dla utrzymania efektywności baterii przez wiele cykli ładowania i rozładowania. Zapewnia ona, że materiał nie ulegnie degradacji, co mogłoby prowadzić do zmniejszenia pojemności i żywotności baterii.

Stabilność w stanie naładowanym:

  • Wartości wskaźnika stabilności materiałów w większości mieszczą się poniżej 0,15
  • Jony wykazujące najwyższą stabilność w stanie naładowanym to Y, Al, Zn, Ca i Mg
  • Jony wykazujące najniższą stabilność w stanie naładowanym to

Stabilność w stanie rozładowanym:

  • Wartości wskaźnika stabilności materiałów w większości mieszczą się poniżej 0,10
  • Jony wykazujące najwyższą stabilność w stanie naładowanym to Y, Mg, Zn oraz Al

Szczególną uwagę przyciąga lit, który charakteryzuje się największą liczbą obserwacji i jednocześnie zajmuje pośrednie miejsce w zestawieniu pod względem wartości wskaźników stabilności.

Zmiana objętości dla danego kroku napięcia z podziałem na jony główne

Working.Ion max_data_volume_mean max_data_volume_median max_data_volume_min max_data_volume_max total
Li 0.0507457 0.0335753 0.0000182 5.1580521 2440
Ca 0.1182812 0.0659500 0.0000784 10.8286680 435
Cs 0.1457824 0.0934072 0.0051639 0.6664421 33
Na 0.1705933 0.0452568 0.0000904 8.0250126 309
Zn 0.2727003 0.0498474 0.0000162 8.0927418 366
Y 0.2960365 0.1421733 0.0022635 4.3714992 93
Al 0.8876411 0.0526704 0.0001877 18.2361563 95
K 0.9206571 0.0763010 0.0000830 16.9232363 107
Rb 1.9653227 0.1017021 0.0031613 20.6965362 50
Mg 2.3445669 0.0472186 0.0002650 293.1932179 423

Najniższą zmianą napięcia charakteryzuje się lit (Li), a najwyższą itr (Y).

Pojemność i gęstość grawimetryczna

Gęstość Grawimetryczna

  • Wskazuje ile energii dostępnej jest w baterii w odniesieniu do jej masy (Wh/kg).
  • Gęstość grawimetryczna informuje, jak efektywnie bateria magazynuje energię w stosunku do swojej wagi. Jest kluczowa dla aplikacji, gdzie ważna jest zarówno pojemność energetyczna, jak i lekkość, np. w samochodach elektrycznych czy dronach.
Working.Ion gravimetric_energy_mean gravimetric_energy_median gravimetric_energy_min gravimetric_energy_max total
Ca 548.2309 490.3278 -212.66060 1950.8674 435
Li 492.9541 450.0437 -583.54584 5926.9497 2440
Y 491.4391 382.3745 1.62500 1766.0037 93
Na 379.5333 354.0919 -551.08126 1754.5647 309
Mg 392.5984 311.1856 -237.08796 2752.4597 423
Al 486.4731 260.6793 -153.46440 2862.7204 95
K 276.6333 233.1158 -534.63162 1553.3791 107
Zn 195.1132 165.4172 -357.54640 989.7295 366
Rb 170.4757 163.3553 -373.40462 1033.5308 50
Cs 188.4780 139.4619 -15.32234 729.0644 33
  • Największą gęstością grawimetryczną charakteryzują się materiały Ca, Li, Y, Na, Mg
  • Najmniejszą gęstością grawimetryczną charakteryzują się materiały Cs, Zn, Rb

Pojemność Grawimetryczna

  • Wskazuje ile energii elektrycznej bateria może przechować w przeliczeniu na jednostkę masy (mAh/g).
  • Im wyższa pojemność grawimetryczna, tym więcej energii bateria może przechowywać przy tej samej masie. Jest to istotne dla urządzeń przenośnych, gdzie zależy nam na maksymalizacji energii przy niewielkiej masie.
  • Największą pojemnością grawimetryczną charakteryzują się materiały Al, Y, Mg, Ca, Zn
  • Najmniejszą pojemnością grawimetryczną charakteryzują się materiały Cs, Rb

Zarówno rubid (Rb) jak i Cez (Cs), które wypadają najgorzej pod względem energii i gestości grawimetrycznej są najrzadziej wykorzystywanymi jonami głównymi.


Poniższy wykres przedstawia zależność między liczbą obserwacji dla najczęściej występujących Wzorów chemicznych materiałów baterii w stanie naładowanym a medianą stabilności w stanie naładowanym. Dla każdego wzoru obliczono miary statyczne, które wyświetlają się po najechaniu na punkt.

Predykcja cech i właściwości baterii

Predykcja pojemności grawimetrycznej metodą regresji

Jako zmienną celu obrano pojemność grawimetryczną.

//TODO delete

Random Forest 

3264 samples
  11 predictor

No pre-processing
Resampling: Cross-Validated (2 fold, repeated 5 times) 
Summary of sample sizes: 1633, 1631, 1632, 1632, 1632, 1632, ... 
Resampling results across tuning parameters:

  mtry  RMSE       Rsquared   MAE       
   2    0.2446747  0.6656663  0.08814636
   6    0.1820564  0.8036072  0.06937326
  11    0.1834491  0.7999853  0.06828544

RMSE was used to select the optimal model using the smallest value.
The final value used for the model was mtry = 6.

Przygotowanie zbioru do trenowania

Ze zbioru usunięto atrybuty:
- ID - nie ma wpływu na zmienną celu - Battery.Formula - bardzo dużo unikalnych wartości, więcej niż połowa rozmiaru zbioru, istnieje ryzyko przeuczenia i nadmiernej segmentacji - Formula.Charge - podobnie jak Battery.Formula - bardzo dużo unikalnych wartości - Formula.Discharge - podobnie jak wyżej

Skalowanie i normalizacja zmiennych

── Data Summary ────────────────────────
                           Values     
Name                       data_scaled
Number of rows             4351       
Number of columns          12         
_______________________               
Column type frequency:                
  numeric                  12         
________________________              
Group variables            None       
                  Df    Sum Sq Mean Sq   F value Pr(>F)    
Battery.Formula 3300 118304814   35850 1.103e+26 <2e-16 ***
Residuals       1050         0       0                     
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Usunięcie zmiennych skorelowanych

[1] "Atomic.Fraction.Charge" "Volumetric.Capacity"    "Max.Voltage.Step"      


Call:
lm(formula = .outcome ~ ., data = dat)

Residuals:
    Min      1Q  Median      3Q     Max 
-7511.8  -367.2   -70.5   348.4  6268.0 

Coefficients:
                            Estimate Std. Error t value Pr(>|t|)    
(Intercept)               -5.712e+02  5.949e+01  -9.602  < 2e-16 ***
Max.Delta.Volume          -1.633e+01  2.050e+00  -7.965 2.31e-15 ***
Average.Voltage            4.323e+02  8.926e+00  48.425  < 2e-16 ***
Volumetric.Capacity        1.301e+00  4.395e-02  29.589  < 2e-16 ***
Atomic.Fraction.Charge    -3.943e+02  2.795e+02  -1.411    0.158    
Atomic.Fraction.Discharge -1.775e+03  2.758e+02  -6.436 1.42e-10 ***
Stability.Discharge       -1.524e+01  4.627e+01  -0.329    0.742    
Steps                      3.295e+02  4.106e+01   8.023 1.45e-15 ***
Max.Voltage.Step           1.977e+02  2.645e+01   7.475 1.01e-13 ***
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Residual standard error: 847.6 on 3038 degrees of freedom
Multiple R-squared:  0.5662,    Adjusted R-squared:  0.5651 
F-statistic: 495.7 on 8 and 3038 DF,  p-value: < 2.2e-16

       RMSE    Rsquared         MAE 
837.0274500   0.6022943 551.1305470 


Call:
lm(formula = .outcome ~ ., data = dat)

Residuals:
    Min      1Q  Median      3Q     Max 
-7497.7  -361.8   -84.9   349.5  6351.9 

Coefficients:
                            Estimate Std. Error t value Pr(>|t|)    
(Intercept)               -5.541e+02  5.525e+01 -10.029  < 2e-16 ***
Max.Delta.Volume          -1.724e+01  1.992e+00  -8.652  < 2e-16 ***
Average.Voltage            4.240e+02  7.984e+00  53.104  < 2e-16 ***
Volumetric.Capacity        1.249e+00  4.117e-02  30.333  < 2e-16 ***
Atomic.Fraction.Charge    -7.329e+02  2.589e+02  -2.831  0.00468 ** 
Atomic.Fraction.Discharge -1.343e+03  2.499e+02  -5.374 8.26e-08 ***
Stability.Discharge        4.296e+01  4.315e+01   0.996  0.31953    
Steps                      3.091e+02  3.737e+01   8.271  < 2e-16 ***
Max.Voltage.Step           2.018e+02  2.515e+01   8.023 1.45e-15 ***
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Residual standard error: 824.3 on 3038 degrees of freedom
Multiple R-squared:  0.5989,    Adjusted R-squared:  0.5979 
F-statistic: 567.1 on 8 and 3038 DF,  p-value: < 2.2e-16
      RMSE   Rsquared        MAE 
892.295500   0.528967 568.000619 
RMSE: 892.2955 

Preprocessing danych

Preprocessing danych obejmuje następujące kroki: - Usunięcie atrybutów, które nie mają wpływu na zmienną celu

[1] "Volumetric.Capacity" "Gravimetric.Energy"  "Stability.Charge"   
  • Usunięcie zmiennych wysoko skorelowanych ze zmienną celu. Atrybuty, które zostały usunięte to Volumetric.Capacity, Gravimetric.Energy, Stability.Charge.
[1] 542
── Data Summary ────────────────────────
                           Values      
Name                       data_cleaned
Number of rows             3809        
Number of columns          12          
_______________________                
Column type frequency:                 
  factor                   4           
  numeric                  8           
________________________               
Group variables            None        
  • Wyczyszczenie wartości odstających. Do identyfikacji outlierów wykorzystano metodę IQR. Usunięto rekordy, które posiadały wartości odstające na co najmniej 2 atrybutach. Zostało usuniętych 542 rekordów.

  • Normalizacja danych

── Data Summary ────────────────────────
                           Values     
Name                       data_scaled
Number of rows             4351       
Number of columns          12         
_______________________               
Column type frequency:                
  factor                   4          
  numeric                  8          
________________________              
Group variables            None       

“Co Warto Wiedzieć o Ogniwach Litowo‑jonowych?” 2024. https://zpe.gov.pl/a/przeczytaj/D10ElmwYT.
“Litowo-Jonowe a Litowo-Polimerowe: Szczegółowe Porównanie.” 2024. https://pkcell.com/pl/porownanie-jonow-litowych-i-polimerow-litowych/.
LS0tDQp0aXRsZTogIlByb2dyYW1vd2FuaWUgdyBSOiBQcm9qZWt0Ig0Kc3VidGl0bGU6ICAgIkFuYWxpemEgYmF6eSBkYW55Y2ggbWF0ZXJpYcWCw7N3IHd5a29yenlzdHl3YW55Y2ggdyB0d29yemVuaXUgYmF0ZXJpaSINCmF1dGhvcjogS2xhdWRpYSBLb3dhbHNrYQ0KZGF0ZTogImByIGZvcm1hdChTeXMudGltZSgpLCAnJWQgJUIgJVknKWAiDQpvdXRwdXQ6DQogIGh0bWxfbm90ZWJvb2s6DQogICAgdG9jOiB0cnVlDQogICAgdG9jX2Zsb2F0OiB0cnVlDQogICAgbGluay1jaXRhdGlvbnM6IHRydWUNCmJpYmxpb2dyYXBoeTogInJlZmVyZW5jZXMuYmliIg0KZWRpdG9yX29wdGlvbnM6IA0KICBjaHVua19vdXRwdXRfdHlwZTogaW5saW5lDQotLS0NCg0KDQojIFdzdMSZcA0KQ2VsZW0gYW5hbGl6eSBiecWCbyB6YmFkYW5pZSB3xYJhxZtjaXdvxZtjaSBtYXRlcmlhxYLDs3cgd3lrb3J6eXN0eXdhbnljaCB3IHR3b3J6ZW5pdSBiYXRlcmlpLg0KDQpgYGB7ciBzZXR1cCwgaW5jbHVkZSA9IEZBTFNFfQ0Ka25pdHI6Om9wdHNfY2h1bmskc2V0KGVjaG8gPSBGQUxTRSwgd2FybmluZyA9IEZBTFNFLCBtZXNzYWdlID0gRkFMU0UsIG91dC53aWR0aCA9ICIxMDAlIikNCnNldC5zZWVkKDExMDgpDQpgYGANCg0KIyMgV3lrb3J6eXN0YW5lIGJpYmxpb3Rla2kNCg0KLSAqKnNraW1yKiogLSBVbW/FvGxpd2lhIHN6eWJraWUgaSBwcnplanJ6eXN0ZSBnZW5lcm93YW5pZSBzdGF0eXN0eWsgb3Bpc293eWNoIGRsYSB6YmlvcsOzdyBkYW55Y2gsIGRvc3RhcmN6YWrEhWMgcG9kc3Vtb3dhbmlhIGRvc3Rvc293YW5lIGRvIHLDs8W8bnljaCB0eXDDs3cgem1pZW5ueWNoLiANCi0gKipjb3JycGxvdCoqIC0gU8WCdcW8eSBkbyB3aXp1YWxpemFjamkgbWFjaWVyenkga29yZWxhY2ppLiANCi0gKipHR2FsbHkqKiAtIFJvenN6ZXJ6YSBtb8W8bGl3b8WbY2kgZ2dwbG90MiwgdW1vxbxsaXdpYWrEhWMgdHdvcnplbmllIHphYXdhbnNvd2FueWNoIHdpenVhbGl6YWNqaSwgdGFraWNoIGphayBtYWNpZXJ6ZSBwYXIgd3lrcmVzw7N3IGN6eSBrb3JlbG9ncmFteSwgY28gamVzdCBwcnp5ZGF0bmUgdyBhbmFsaXppZSB3aWVsb3d5bWlhcm93ZWouIA0KLSAqKmRwbHlyKiogLSBaYXBld25pYSB6ZXN0YXcgZnVua2NqaSBkbyBtYW5pcHVsYWNqaSBkYW55bWkgdyBzcG9zw7NiIGRla2xhcmF0eXdueSBpIGN6eXRlbG55LCB1bW/FvGxpd2lhasSFYyBmaWx0cm93YW5pZSwgc29ydG93YW5pZSwgZ3J1cG93YW5pZSBvcmF6IGFncmVnb3dhbmllIGRhbnljaCB3IHJhbWFjaCB6xYJvxbxvbnljaCBvcGVyYWNqaS4gDQotICoqcGxvdGx5KiogLSBQb3p3YWxhIG5hIHR3b3J6ZW5pZSBpbnRlcmFrdHl3bnljaCB3eWtyZXPDs3cuIA0KLSAqKmNhcmV0KiogLSBVxYJhdHdpYSBwcm9jZXMgYnVkb3d5IG1vZGVsaSBwcmVkeWtjeWpueWNoLCBvZmVydWrEhWMgbmFyesSZZHppYSBkbyBwcnp5Z290b3dhbmlhIGRhbnljaCwgc2VsZWtjamkgY2VjaCwgdHVuaW5ndSBoaXBlcnBhcmFtZXRyw7N3IG9yYXogb2NlbnkgbW9kZWxpIHcgc3DDs2pueSBpIHppbnRlZ3Jvd2FueSBzcG9zw7NiLg0KDQoNCmBgYHtyIHJlc3VsdHM9J2hpZGUnLCBlY2hvPVRSVUV9DQpsaWJyYXJ5KHNraW1yKQ0KbGlicmFyeShjb3JycGxvdCkNCmxpYnJhcnkoR0dhbGx5KQ0KbGlicmFyeShkcGx5cikNCmxpYnJhcnkocGxvdGx5KQ0KbGlicmFyeSgiSG1pc2MiKQ0KbGlicmFyeShtbGJlbmNoKQ0KbGlicmFyeShjYXJldCkNCmxpYnJhcnkocmxhbmcpDQpsaWJyYXJ5KGtuaXRyKQ0KbGlicmFyeShEVCkNCmxpYnJhcnkoZHBseXIpDQpsaWJyYXJ5KGdncGxvdDIpDQpsaWJyYXJ5KGdyaWRFeHRyYSkNCmxpYnJhcnkoaGVyZSkNCmxpYnJhcnkodGlkeXZlcnNlKQ0KbGlicmFyeShzY2FsZXMpDQpgYGANCg0KIyMgSmFrIHd5Z2zEhWRhasSFIGRhbmU/DQoNCmBgYHtyIGxvYWQgZGF0YSwgY2FjaGUgPSBUUlVFLCByZXN1bHRzPUZBTFNFfQ0KI3VybGZpbGU9Imh0dHBzOi8vcmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbS9LbGF1ZGlhSy9CYXR0ZXJ5LW1hdGVyaWFscy1hbmFseXNpcy9yZWZzL2hlYWRzL21hc3Rlci9tcF9iYXR0ZXJpZXMuY3N2Ig0KI2RhdGEgPC0gcmVhZC5jc3YodXJsKHVybGZpbGUpKQ0KDQpkYXRhIDwtIHJlYWQuY3N2KCJEOlxcc3R1ZGlhXFxtYWdpc3RlcmthXFxaRURcXFByb2pla3RfUlxcbXBfYmF0dGVyaWVzLmNzdiIpDQoNCmRhdGEkU3RlcHMgPC0gYXMuZmFjdG9yKGRhdGEkU3RlcHMpDQpkYXRhJFdvcmtpbmcuSW9uIDwtIGFzLmZhY3RvcihkYXRhJFdvcmtpbmcuSW9uKQ0KZGF0YSRGb3JtdWxhLkNoYXJnZSA8LSBhcy5mYWN0b3IoZGF0YSRGb3JtdWxhLkNoYXJnZSkNCmRhdGEkRm9ybXVsYS5EaXNjaGFyZ2UgPC0gYXMuZmFjdG9yKGRhdGEkRm9ybXVsYS5EaXNjaGFyZ2UpDQpgYGANCg0KVyBjZWx1IHppbHVzdHJvd2FuaWEgemF3YXJ0b8WbY2kgemJpb3J1IGRhbnljaCwgd3nFm3dpZXRsb25vIGtpbGthIHBpZXJ3c3p5Y2ggd2llcnN6eSB6YmlvcnUsIGFieSB6YXByZXplbnRvd2HEhyBzdHJ1a3R1csSZIHRhYmVsaSwgbmF6d3kgem1pZW5ueWNoIG9yYXogcHJ6eWvFgmFkeSB3YXJ0b8WbY2ksIGt0w7NyZSBvbmUgcHJ6eWptdWrEhS4NCg0KYGBge3IgZGlzcGxheS1kYXRhLCBlY2hvPUZBTFNFfQ0KaGVhZChkYXRhKQ0KYGBgDQoNCiMjIEF0cnlidXR5DQoNClcgcG9uacW8c3plaiB0YWJlbGkgcHJ6ZWRzdGF3aW9ubyB6bmFqZHVqxIVjZSBzacSZIHcgemJpb3J6ZSBhdHJ5YnV0eSBvcmF6IGljaCBkZWZpbmljamUuIA0KDQp8IEF0cnlidXQgICAgICAgICAgIHwgT3BpcyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHwNCnwtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS18LS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS18DQp8ICoqQmF0dGVyeSBJRCoqICAgICAgICAgICAgICAgIHwgSWRlbnR5ZmlrYXRvciBiYXRlcmlpLiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHwNCnwgKipCYXR0ZXJ5IEZvcm11bGEqKiAgICAgICAgICAgfCBXesOzciBjaGVtaWN6bnkgbWF0ZXJpYcWCdSBiYXRlcmlpLiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB8DQp8ICoqV29ya2luZyBJb24qKiAgICAgICAgICAgICAgIHwgR8WCw7N3bnkgam9uLCBrdMOzcnkgb2Rwb3dpYWRhIHphIHRyYW5zcG9ydCDFgmFkdW5rdSB3IGJhdGVyaWkuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB8DQp8ICoqRm9ybXVsYSBDaGFyZ2UqKiAgICAgICAgICAgIHwgV3rDs3IgY2hlbWljem55IG1hdGVyaWHFgnUgYmF0ZXJpaSB3IHN0YW5pZSBuYcWCYWRvd2FueW0uICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHwNCnwgKipGb3JtdWxhIERpc2NoYXJnZSoqICAgICAgICAgfCBXesOzciBjaGVtaWN6bnkgbWF0ZXJpYcWCdSBiYXRlcmlpIHcgc3RhbmllIHJvesWCYWRvd2FueW0uICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgfA0KfCAqKk1heCBEZWx0YSBWb2x1bWUqKiAgICAgICAgICB8IFptaWFuYSBvYmrEmXRvxZtjaSB3ICUgZGxhIGRhbmVnbyBrcm9rdSBuYXBpxJljaWEgemEgcG9tb2PEhSB3em9ydSA6IG1heChjaGFyZ2UsIGRpc2NoYXJnZSkvbWluKGNoYXJnZSwgZGlzY2hhcmdlKSAtMS4gfA0KfCAqKkF2ZXJhZ2UgVm9sdGFnZSoqICAgICAgICAgICB8IMWacmVkbmllIG5hcGnEmWNpZSBkbGEgcG9zemN6ZWfDs2xuZWdvIGtyb2t1IG5hcGnEmWNpYS4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgfA0KfCAqKkdyYXZpbWV0cmljIENhcGFjaXR5KiogICAgICB8IFBvamVtbm/Fm8SHIGdyYXdpbWV0cnljem5hLCBjenlsaSBpbG/Fm8SHIGVuZXJnaWkgbmEgamVkbm9zdGvEmSBtYXN5IChtQWgvZykuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHwNCnwgKipWb2x1bWV0cmljIENhcGFjaXR5KiogICAgICAgfCBQb2plbW5vxZvEhyB3b2x1bWV0cnljem5hLCBjenlsaSBpbG/Fm8SHIGVuZXJnaWkgbmEgamVkbm9zdGvEmSBvYmrEmXRvxZtjaSAobUFoL2NtwrMpLiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB8DQp8ICoqR3JhdmltZXRyaWMgRW5lcmd5KiogICAgICAgIHwgR8SZc3RvxZvEhyBlbmVyZ2lpIHcgb2RuaWVzaWVuaXUgZG8gbWFzeSBiYXRlcmlpIChXaC9rZykuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHwNCnwgKipWb2x1bWV0cmljIEVuZXJneSoqICAgICAgICAgfCBHxJlzdG/Fm8SHIGVuZXJnaWkgdyBvZG5pZXNpZW5pdSBkbyBvYmrEmXRvxZtjaSBiYXRlcmlpIChXaC9MKS4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB8DQp8ICoqQXRvbWljIEZyYWN0aW9uIENoYXJnZSoqICAgIHwgVWR6aWHFgiBhdG9tb3d5IHNrxYJhZG5pa8OzdyB3IHN0YW5pZSBuYcWCYWRvd2FueW0uICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB8DQp8ICoqQXRvbWljIEZyYWN0aW9uIERpc2NoYXJnZSoqIHwgVWR6aWHFgiBhdG9tb3d5IHNrxYJhZG5pa8OzdyB3IHN0YW5pZSByb3rFgmFkb3dhbnltLiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB8DQp8ICoqU3RhYmlsaXR5IENoYXJnZSoqICAgICAgICAgIHwgV3NrYcW6bmlrIHN0YWJpbG5vxZtjaSBtYXRlcmlhxYJ1IHcgc3RhbmllIG5hxYJhZG93YW55bS4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB8DQp8ICoqU3RhYmlsaXR5IERpc2NoYXJnZSoqICAgICAgIHwgV3NrYcW6bmlrIHN0YWJpbG5vxZtjaSBtYXRlcmlhxYJ1IHcgc3RhbmllIHJvesWCYWRvd2FueW0uICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB8DQp8ICoqU3RlcHMqKiAgICAgICAgICAgICAgICAgICAgIHwgTGljemJhIG9kcsSZYm55Y2gga3Jva8OzdyBuYXBpxJljaWEgb2QgcGXFgm5lZ28gbmHFgmFkb3dhbmlhIGRvIHJvesWCYWRvd2FuYSwgb3BhcnRhIG5hIHN0YWJpbG55Y2ggc3RhbmFjaCBwb8WbcmVkbmljaC4gICB8DQp8ICoqTWF4IFZvbHRhZ2UgU3RlcCoqICAgICAgICAgIHwgTWFrc3ltYWxuYSBiZXp3emdsxJlkbmEgcsOzxbxuaWNhIG1pxJlkenkgc8SFc2llZG5pbWkga3Jva2FtaSBuYXBpxJljaWEuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHwNCg0KIyMgQ2hhcmFrdGVyeXN0eWthIHpiaW9ydSBkYW55Y2gNCg0KKipaYmnDs3IgZGFueWNoIHphd2llcmEgYHIgbmNvbChkYXRhKWAgYXRyeWJ1dMOzdyBpIGByIG5yb3coZGF0YSlgIHJla29yZMOzdy4qKg0KDQpgYGB7ciBjb3VudC1uYS12YWx1ZXMsIGVjaG89RkFMU0V9DQpzdW1fbmEgPC0gc3VtKGlzLm5hKGRhdGEpKQ0KYGBgDQoNCioqU3VtYSBicmFrdWrEhWN5Y2ggd2FydG/Fm2NpIHcgemJpb3J6ZTogYHIgc3VtX25hYC4qKg0KDQpgYGB7ciBtaXNzaW5nLXZhbHVlc30NCmthYmxlKGNvbFN1bXMoaXMubmEoZGF0YSkpLCBjb2wubmFtZXMgPSBjKCJMaWN6YmEgYnJha3VqxIVjeWNoIHdhcnRvxZtjaSIpLCBjYXB0aW9uID0gIkxpY3piYSBicmFrdWrEhWN5Y2ggd2FydG/Fm2NpIHcga29sdW1uYWNoIikNCmBgYA0KDQoqKlN1bWEgZHVwbGlrYXTDs3c6IGByIHN1bShkdXBsaWNhdGVkKGRhdGEpKWAuKioNCg0KWmJpw7NyIGRhbnljaCBuaWUgemF3aWVyYSBicmFrdWrEhWN5Y2ggd2FydG/Fm2NpIGFuaSBkdXBsaWthdMOzdywgd2nEmWMgZGFuZSBuaWUgd3ltYWdhasSFIGN6eXN6Y3plbmlhLg0KDQpgYGB7ciBjb2x1bW4tdHlwZXMtc3VtbWFyeX0NCnNraW1fc3VtbWFyeSA8LSBza2ltKGRhdGEpDQoNCm51bV9jaGFyYWN0ZXIgPC0gc2tpbV9zdW1tYXJ5ICU+JSBmaWx0ZXIoc2tpbV90eXBlID09ICJjaGFyYWN0ZXIiKSAlPiUgbnJvdygpDQpudW1fbnVtZXJpYyA8LSBza2ltX3N1bW1hcnkgJT4lIGZpbHRlcihza2ltX3R5cGUgPT0gIm51bWVyaWMiKSAlPiUgbnJvdygpDQpudW1fbG9naWNhbCA8LSBza2ltX3N1bW1hcnkgJT4lIGZpbHRlcihza2ltX3R5cGUgPT0gImxvZ2ljYWwiKSAlPiUgbnJvdygpDQpgYGANCg0KWmJpw7NyIHphd2llcmE6IFwNCi0ga29sdW1ueSB6bmFrb3dlOiBgciBudW1fY2hhcmFjdGVyYCwgXA0KLSBrb2x1bW55IG51bWVyeWN6bmU6IGByIG51bV9udW1lcmljYCxcDQotIGtvbHVtbnkgbG9naWN6bmU6IGByIG51bV9sb2dpY2FsYCBcDQoNCmBgYHtyIG51bWVyaWNhbC1hdHRyaWJ1dGVzLCBlY2hvPUZBTFNFfQ0KbnVtZXJpY2FsX2F0dHJzIDwtIGNvbG5hbWVzKHNlbGVjdChkYXRhLCAoTWF4LkRlbHRhLlZvbHVtZSA6IE1heC5Wb2x0YWdlLlN0ZXApKSkNCmBgYA0KDQpgYGB7ciBwcmV0dHktdGFibGUsICBlY2hvPUZBTFNFfQ0KcHJldHR5VGFibGUgPC0gZnVuY3Rpb24odGFibGVfZGYsIHJvdW5kX2RpZ2l0cz0yKSB7IA0KICBEVDo6ZGF0YXRhYmxlKHRhYmxlX2RmLCBzdHlsZT0iYm9vdHN0cmFwIiwgZmlsdGVyID0gInRvcCIsIHJvd25hbWVzID0gRkFMU0UsIGV4dGVuc2lvbnMgPSAiQnV0dG9ucyIsIG9wdGlvbnMgPSBsaXN0KGRvbSA9ICdCZnJ0aXAnLHNjcm9sbFggPSBUUlVFLCBhdXRvV2lkdGggPSBUUlVFKSkgJT4lIA0KICAgIGZvcm1hdFJvdW5kKG5hbWVzKGRwbHlyOjpzZWxlY3RfaWYodGFibGVfZGYsIGlzLm51bWVyaWMpKSwgcm91bmRfZGlnaXRzKQ0KfQ0KYGBgDQoNCiMgQW5hbGl6YSB6YmlvcnUgZGFueWNoDQoNClcgdGVqIGN6xJnFm2NpIHpvc3RhbmllIHByemVwcm93YWR6b25hIGFuYWxpemEgd2FydG/Fm2NpIGF0cnlidXTDs3cgdyB6YmlvcnplIGRhbnljaC4gQ2VsZW0gdGVqIGFuYWxpenkgamVzdCB6cm96dW1pZW5pZSByb3prxYJhZHUsIHptaWVubm/Fm2NpIG9yYXoga2x1Y3pvd3ljaCBjZWNoIHBvc3pjemVnw7NsbnljaCBhdHJ5YnV0w7N3LCBjbyBwb3p3b2xpIG5hIGxlcHN6xIUgaW50ZXJwcmV0YWNqxJkgZGFueWNoLiBBbmFsaXphIG9iZWptaWUgcsOzxbxuZSBtZXRvZHkgd2l6dWFsaXphY2ppLCB0YWtpZSBqYWsgaGlzdG9ncmFteSwgd3lrcmVzeSBnxJlzdG/Fm2NpIG9yYXogd3lrcmVzeSBwdWRlxYJrb3dlLCBrdMOzcmUgdW1vxbxsaXdpxIUgc3p5YmtpZSB3eWNod3ljZW5pZSBpc3RvdG55Y2ggdHJlbmTDs3csIHdhcnRvxZtjaSBvZHN0YWrEhWN5Y2ggb3JheiBjaGFyYWt0ZXJ5c3R5a2kgcm96a8WCYWR1IGRhbnljaC4NCg0KIyMgUm96a8WCYWR5IGF0cnlidXTDs3cNCg0KIyMjIEF0cnlidXR5IG51bWVyeWN6bmUNCg0KU2VrY2phIG9iZWptdWplIHdpenVhbGl6YWNqxJkgcm96a8WCYWTDs3cgd2FydG/Fm2NpIGRsYSBhdHJ5YnV0w7N3IG51bWVyeWN6bnljaC4gUG8gbGV3ZWogc3Ryb25pZSB6bmFqZHVqZSBzacSZIGhpc3RvZ3JhbSwga3TDs3J5IGlsdXN0cnVqZSBjesSZc3RvxZvEhyB3eXN0xJlwb3dhbmlhIHLDs8W8bnljaCB3YXJ0b8WbY2kgYXRyeWJ1dHUgcHJ6eXBvcnrEhWRrb3dhbnljaCBkbyBva3JlxZtsb25laiBsaWN6YnkgcHJ6ZWR6aWHFgsOzdy4gDQpQb21hcmHFhGN6b3d5IGtvbG9yIHJlcHJlemVudHVqZSBsaW5pxJkgZ8SZc3RvxZtjaSByb3prxYJhZHUgKHR6dy4gZGVuc2l0eSBwbG90KS4gV3lrcmVzIGfEmXN0b8WbY2kgamVzdCB1xbx5d2FueSBkbyB3aXp1YWxpemFjamkga3N6dGHFgnR1IHJvemvFgmFkdSBkYW55Y2gsIHBvendhbGFqxIVjIG5hIGxlcHN6ZSB6cm96dW1pZW5pZSBqZWdvIGZvcm15IHcgcG9yw7N3bmFuaXUgZG8gaGlzdG9ncmFtdS4NCk5hIHd5a3Jlc2llIHpuYWpkdWplIHNpxJkgcsOzd25pZcW8IGN6ZXJ3b25hIGxpbmlhIHBpb25vd2EsIG96bmFjemFqxIVjYSDFm3JlZG5pxIUgd2FydG/Fm8SHIGF0cnlidXR1LCBjbyBwb3p3YWxhIG5hIHN6eWJrxIUgb2NlbsSZIGplZ28gY2VudHJhbG5lZ28gcG/Fgm/FvGVuaWEuXA0KUG8gcHJhd2VqIHN0cm9uaWUgem5hamR1amUgc2nEmSB3eWtyZXMgcHVkZcWCa293eSAodHp3LiBib3hwbG90KSwga3TDs3J5IHdpenVhbGl6dWplIHJvenByb3N6ZW5pZSB3YXJ0b8WbY2kgaSBwb3p3YWxhIG5hIGlkZW50eWZpa2FjasSZIHdhcnRvxZtjaSBvZHN0YWrEhWN5Y2guDQoNCg0KYGBge3IgZGF0YS1oaXN0b2dyYW0tYm94cGxvdCwgZmlnLndpZHRoPTE0fQ0KcGxvdF9saXN0IDwtIGxpc3QoKQ0KDQpmb3IgKGF0dHJfbmFtZSBpbiBudW1lcmljYWxfYXR0cnMpIHsNCiAgbWluX3ZhbHVlIDwtIG1pbihkYXRhW1thdHRyX25hbWVdXSwgbmEucm0gPSBUUlVFKSAgDQogIG1heF92YWx1ZSA8LSBtYXgoZGF0YVtbYXR0cl9uYW1lXV0sIG5hLnJtID0gVFJVRSkNCiAgbWVhbl92YWx1ZSA8LSBtZWFuKGRhdGFbW2F0dHJfbmFtZV1dLCBuYS5ybSA9IFRSVUUpDQogIA0KICBwX2hpc3RvZ3JhbSA8LSBnZ3Bsb3QoZGF0YSwgYWVzX3N0cmluZyh4ID0gYXR0cl9uYW1lKSkgKw0KICAgIGdlb21faGlzdG9ncmFtKGFlcyh5ID0gLi5kZW5zaXR5Li4pLA0KICAgICAgICAgICAgICAgICAgIGJpbndpZHRoID0gKG1heF92YWx1ZSAtIG1pbl92YWx1ZSkgLyAzMCwNCiAgICAgICAgICAgICAgICAgICBmaWxsID0gImRhcmtibHVlIiwgDQogICAgICAgICAgICAgICAgICAgY29sb3IgPSAiYmxhY2siLCANCiAgICAgICAgICAgICAgICAgICBhbHBoYSA9IDAuMykgKw0KICAgIGdlb21fZGVuc2l0eShjb2xvciA9ICJkYXJrb3JhbmdlIiwgc2l6ZSA9IDIpICsNCiAgICBnZW9tX3ZsaW5lKGFlcyh4aW50ZXJjZXB0ID0gbWVhbl92YWx1ZSksIGNvbG9yID0gInJlZCIsIGxpbmV0eXBlID0gImRhc2hlZCIsIHNpemUgPSAxKSArDQogICAgbGFicyh0aXRsZSA9IHBhc3RlKCJIaXN0b2dyYW0gZGxhIiwgYXR0cl9uYW1lKSwNCiAgICAgICAgIHggPSBhdHRyX25hbWUsDQogICAgICAgICB5ID0gIkxpY3piYSBvYnNlcndhY2ppIikgKw0KICBzY2FsZV94X2NvbnRpbnVvdXMobGltaXRzID0gYyhtaW5fdmFsdWUgLSAxLCBtYXhfdmFsdWUpKSArDQogIHRoZW1lX21pbmltYWwoKSArDQogIHRoZW1lKA0KICAgICBwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemUgPSAyMCkNCiAgKQ0KICANCiAgDQogIHBfYm94cGxvdCA8LSBnZ3Bsb3QoZGF0YSwgYWVzX3N0cmluZyh5ID0gYXR0cl9uYW1lKSkgKw0KICAgIGdlb21fYm94cGxvdCgNCiAgICAgIGZpbGwgPSAicHVycGxlIiwgDQogICAgICBjb2xvciA9ICJibGFjayIsIA0KICAgICAgb3V0bGllci5zaXplID0gMiwgDQogICAgICBvdXRsaWVyLmNvbG91ciA9ICJyZWQiLA0KICAgICAgb3V0bGllci5zaGFwZSA9IDE2DQogICAgKSArDQogICAgbGFicyh0aXRsZSA9IHBhc3RlKCJXeWtyZXMgcHVkZcWCa293eSBkbGEiLCBhdHRyX25hbWUpLA0KICAgICAgICAgeSA9IGF0dHJfbmFtZSkgKw0KICAgIHRoZW1lX21pbmltYWwoKSArDQogICAgdGhlbWUoDQogICAgIHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDIwKSwNCiAgICBwbG90Lm1hcmdpbiA9IG1hcmdpbih0ID0gMjAsIHIgPSAyMCwgYiA9IDIwLCBsID0gMjApDQogICAgKQ0KICAgIA0KICANCiAgZ3JpZF9wbG90IDwtIGdyaWQuYXJyYW5nZShwX2hpc3RvZ3JhbSwgcF9ib3hwbG90LCBuY29sID0gMikNCiAgDQogIHBsb3RfbGlzdFtbYXR0cl9uYW1lXV0gPC0gZ3JpZF9wbG90DQp9DQoNCmBgYA0KV2nEmWtzem/Fm8SHIHJvemvFgmFkw7N3IGplc3QgcHJhd29za2/Fm25hLCBjbyBvem5hY3phLCDFvGUgd2nEmWtzem/Fm8SHIHdpxJlrc3pvxZvEhyB3YXJ0b8WbY2kgamVzdCBtbmllanN6eWNoIG5pxbwgxZtyZWRuaWEuIA0KDQotIE1heCBEZWx0YSBWb2x1bWUgLSBEYW5lIHPEhSB3eXJhxbpuaWUgc2t1cGllbmUgcHJ6eSB6ZXJ6ZSwgb2JlY25lIHPEhSBuaWVsaWN6bmUgcHJ6eXBhZGtpIG9kc3RhasSFY2UuDQotIE1heCBWb2x0YWdlIFN0ZXAgLSBEYW5lIHPEhSB3eXJhxbpuaWUgc2t1cGllbmUgcHJ6eSB6ZXJ6ZSwgY28gc3VnZXJ1amUsIMW8ZSB3acSZa3N6b8WbxIcgZGFueWNoIHByenlqbXVqZSB3YXJ0b8WbY2kgYmxpc2tpZSB6ZXJ1LiBPYmVjbmUgc8SFIG5pZWxpY3puZSBwcnp5cGFka2kgb2RzdGFqxIVjZS4NCg0KIyMjIEfFgsOzd25lIGpvbnkNCg0KVGFiZWxhIHByemVkc3Rhd2lhIG1lZGlhbnkgd2FydG/Fm2NpIGF0cnlidXLDs3cgbnVtZXJ5Y3pueWNoLCBkbGEgcG9zemN6ZWfDs2xueWNoIGdydXAgZ8WCw7N3bmVnbyBqb251IHRyYW5zcG9ydHVqxIVjZWdvIMWCYWR1bmVrIChXb3JraW5nIElvbikuDQoNCmBgYHtyIGlvbl9tZWFuX3N1bW1hcnl9DQoNCmlvbl9tZWFuX3N1bSA8LSAgZGF0YSAlPiUNCiAgICBzZWxlY3QoV29ya2luZy5Jb24sIE1heC5EZWx0YS5Wb2x1bWU6U3RhYmlsaXR5LkRpc2NoYXJnZSkgJT4lDQogICAgZ3JvdXBfYnkoV29ya2luZy5Jb24pICU+JQ0KICAgIHN1bW1hcmlzZShhY3Jvc3MoZXZlcnl0aGluZygpLCBtZWRpYW4pKQ0KDQpwcmV0dHlUYWJsZShpb25fbWVhbl9zdW0pDQpgYGANCg0KYGBge3IgaW9uX2Rpc3RyaWJ1dGlvbn0NCg0KZGF0YSAlPiUNCiAgZ3JvdXBfYnkoV29ya2luZy5Jb24pICU+JQ0KICBzdW1tYXJpc2UodG90YWxfaW9uID0gbigpKSAlPiUNCiAgZ2dwbG90KCkgKw0KICAgbGFicyh0aXRsZSA9IHBhc3RlKCJSb3prxYJhZCBnxYLDs3dueWNoIGpvbsOzdyBvZHBvd2lhZGFqxIVjeWNoIHphIHRyYW5zcG9ydCDFgmFkdW5rdSB3IGJhdGVyaWkiKSwNCiAgICAgICAgICAgeCA9ICJXb3JraW5nLklvbiIsDQogICAgICAgICAgIHkgPSAiQ291bnQiKSArDQogICAgICBnZW9tX2JhcihhZXMoeCA9IHJlb3JkZXIoV29ya2luZy5Jb24sIHRvdGFsX2lvbiksIHkgPSB0b3RhbF9pb24sIGZpbGwgPSBXb3JraW5nLklvbiksIHN0YXQgPSAiaWRlbnRpdHkiKSArDQogICAgICB0aGVtZV9taW5pbWFsKCkgDQpgYGANCk5hIHByemVkc3Rhd2lvbnltIHd5a3Jlc2llIHphcHJlemVudG93YW5vIHJvemvFgmFkIGfFgsOzd255Y2ggam9uw7N3IHXFvHl3YW55Y2ggZG8gdHJhbnNwb3J0dSDFgmFkdW5rdSB3IGJhdGVyaWFjaC4gV3lyYcW6bmllIGRvbWludWplIGxpdCAoTGkpLCBrdMOzcnkgd3lzdMSZcHVqZSB6bmFjem5pZSBjesSZxZtjaWVqIG5pxbwgaW5uZSBqb255IHRqLiBwcmF3aWUgMjUwMCByYXp5LiBTdWdlcnVqZSB0byBwb3dzemVjaG5lIHphc3Rvc293YW5pZSB0ZWNobm9sb2dpaSBvcGFydHljaCBuYSBsaXRvd28tam9ub3d5Y2ggcm96d2nEhXphbmlhY2gsIGNvIGplc3QgemdvZG5lIHogaWNoIHN6ZXJva2ltIHd5a29yenlzdGFuaWVtIHcgcHJ6ZW15xZtsZSBlbGVrdHJvbmlraSBpIG1hZ2F6eW5vd2FuaWEgZW5lcmdpaS4gDQpTemN6ZWfDs2xuxIUgemFsZXTEhSBiYXRlcmlpIGxpdG93by1qb25vd3ljaCBqZXN0ICB3eXNva8SFIGfEmXN0b8WbxIcgZW5lcmdpaS4gVG8gem5hY3p5LCDFvGUgbW9nxIUgbWFnYXp5bm93YcSHIGR1xbzEhSBpbG/Fm8SHIGVuZXJnaWkgcHJ6eSBuaWV3aWVsa2ljaCByb3ptaWFyYWNoIGkgbmlza2llaiB3YWR6ZSwgY28gY3p5bmkgamUgZG9za29uYcWCeW0gcm96d2nEhXphbmllbSBkbGEgcHJ6ZW5vxZtueWNoIHVyesSFZHplxYQsIHRha2ljaCBqYWsgbGFwdG9weSBpIHRhYmxldHkgW0Bwb3Jvd25hbmllLWxpdG93eWNoLWJhdGVyaWldLiBXIHplc3Rhd2llbml1IHBpZXJ3aWFzdGvDs3cgbGl0IHBsYXN1amUgc2nEmSBuYSBkcnVnaW0gbWllanNjdSBwb2Qgd3pnbMSZZGVtIGdyYXdpbWV0cmN6bmVqIGfEmXN0b8WbY2kgZW5lcmdpaSwgemFyYXogemEgd2FwbmllbS4gXA0KUG96b3N0YcWCZSBqb255LCB0YWtpZSBqYWsgd2FwxYQgKENhKSwgbWFnbmV6IChNZyksIGkgY3luayAoWm4pLCByw7N3bmllxbwgem5hamR1asSFIHphc3Rvc293YW5pZSwgYWxlIHcgem5hY3puaWUgbW5pZWpzenltIHpha3Jlc2llLiBPYmVjbm/Fm8SHIGpvbsOzdyB0YWtpY2ggamFrIHPDs2QgKE5hKSBpIHBvdGFzIChLKSBtb2fEhSB3c2thenl3YcSHIG5hIGJhZGFuaWEgbmFkIGFsdGVybmF0eXdhbWkgZGxhIGxpdHUsIGplZG5hayBpY2ggemFzdG9zb3dhbmllIGplc3Qgb2JlY25pZSBvZ3Jhbmljem9uZS4NCg0KLS0tLS0tLS0tLS0tDQoNClBvbmnFvGVqIHpuYWpkdWrEhSBzacSZIGludGVya2F0eXduZSB3eWtyZXN5IHB1ZGXFgmtvd2UgZGxhIGthxbxkZWogem1pZW5uZWogbnVtZXJ5Y3puZWogdyB6YmlvcnplIGRhbnljaCB6IHBvZHppYcWCZW0gbmEgZ8WCw7N3bmUgam9ueS4gV3lrcmVzeSB0ZSB1bW/FvGxpd2lhasSFIGVrc3Bsb3JhY2rEmSByb3prxYJhZHUgd2FydG/Fm2NpLCBpZGVudHlmaWthY2rEmSBwb3RlbmNqYWxueWNoIHdhcnRvxZtjaSBvZHN0YWrEhWN5Y2ggb3JheiBwb3LDs3duYW5pZSB6bWllbm5vxZtjaSB3IGthxbxkZWogem1pZW5uZWogZGxhIHBvc3plZ8OzbG55Y2ggam9uw7N3Lg0KDQpgYGB7ciBpbnRlcmFjdGl2ZV9ib3hwbG90cywgcmVzdWx0cz0naGlkZScsIGZpZy5rZWVwID0gJ25vbmUnLCBmaWcud2lkdGg9MTR9DQpmb3IgKGF0dHJfbmFtZSBpbiBuYW1lcyhudW1iZXJfYXR0cl9kYXRhKSkgew0KICBwIDwtIHBsb3RfbHkoDQogICAgZGF0YSwgDQogICAgeSA9IH5nZXQoYXR0cl9uYW1lKSwNCiAgICB0eXBlID0gImJveCIsDQogICAgYm94cG9pbnRzID0gImFsbCIsDQogICAgaml0dGVyID0gMC4zLA0KICAgIHBvaW50cG9zID0gLTEuOCwNCiAgICAjdGV4dCA9IH5wYXN0ZSgiV29ya2luZyBJb246ICIsIFdvcmtpbmcuSW9uLCAiPGJyPkZvcm11bGEiKSwNCiAgICBob3ZlckluZm8gPSAidGV4dCIsDQogICAgY29sb3IgPSB+V29ya2luZy5Jb24NCiAgICAgICAgICAgICAgICAgICANCiAgKSAlPiUNCiAgICBsYXlvdXQoDQogICAgICB0aXRsZSA9IHBhc3RlKCJCb3hwbG90IG9mIiwgYXR0cl9uYW1lKSwNCiAgICAgIHlheGlzID0gbGlzdCh0aXRsZSA9IGF0dHJfbmFtZSkNCiAgICApDQoNCiAgcHJpbnQocCkNCn0NCg0KYGBgDQoNCiMjIyBXem9yeSBjaGVtaWN6bmUgbWF0ZXJpYcWCdSBiYXRlcmlpDQoNCmBgYHtyIGZvcm11bGEtY2hhcmdlLWRpc3RyaWJ1dGlvbiwgZWNobyA9IEZBTFNFfQ0KZm9ybXVsYV9jaGFyZ2Vfc3VtbWFyeSA8LSBkYXRhICU+JQ0KICBncm91cF9ieShGb3JtdWxhLkNoYXJnZSkgJT4lDQogIHN1bW1hcmlzZSh0b3RhbCA9IG4oKSkgJT4lDQogIGFycmFuZ2UoZGVzYyh0b3RhbCkpDQoNCnBlcmNlbnRpbGVfOTkgPC0gcXVhbnRpbGUoc2VsZWN0KGZvcm11bGFfY2hhcmdlX3N1bW1hcnksIHRvdGFsKSwgcHJvYnMgPSAwLjk5LCBuYS5ybSA9IFRSVUUpDQpmb3JtdWxhX2NoYXJnZV92YWx1ZXNfOTlfcGVyY2VudGlsZSA8LSBmb3JtdWxhX2NoYXJnZV9zdW1tYXJ5ICU+JQ0KICBmaWx0ZXIodG90YWwgPj0gcGVyY2VudGlsZV85OSkNCg0Ka2FibGUoZm9ybXVsYV9jaGFyZ2VfdmFsdWVzXzk5X3BlcmNlbnRpbGUpDQoNCmZvcm11bGFfY2hhcmdlX3ZhbHVlc185OV9wZXJjZW50aWxlICU+JQ0KICBnZ3Bsb3QoKSArDQogICBsYWJzKHRpdGxlID0gcGFzdGUoIld6w7NyeSBjaGVtaWN6bmUgbWF0ZXJpYcWCdSBiYXRlcmlpIHcgc3RhbmllIG5hxYJhZG93YW55bSIpLA0KICAgICAgICAgICB4ID0gIld6w7NyIHcgc3RhbmllIG5hxYJhZG93YW55bSIsDQogICAgICAgICAgIHkgPSAiTGljemJhIG9ic2Vyd2FjamkiKSArDQogICAgICBnZW9tX2JhcihhZXMoeCA9IHJlb3JkZXIoRm9ybXVsYS5DaGFyZ2UsIHRvdGFsKSwgeSA9IHRvdGFsLCBmaWxsID0gRm9ybXVsYS5DaGFyZ2UpLCBzdGF0ID0gImlkZW50aXR5IiwgIHdpZHRoID0gMC41KSArDQogICAgICB0aGVtZSgNCiAgICAgICAgdGV4dCA9IGVsZW1lbnRfdGV4dChzaXplID0gMTIpLA0KICAgICAgICBheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDkwLCBoanVzdCA9IDEsIHNpemUgPSA4KQ0KICAgICAgKQ0KYGBgDQoNCld5a3JlcyBwcnplZHN0YXdpYSBsaWN6YsSZIHd5c3TEhXBpZcWEIHLDs8W8bnljaCB3em9yw7N3IGNoZW1pY3pueWNoIG1hdGVyaWHFgsOzdyBiYXRlcmlpIHcgc3RhbmllIG5hxYJhZG93YW55bS4gVyB6YmlvcnplIGplc3QgYHIgbGVuZ3RoKHVuaXF1ZShkYXRhJEZvcm11bGEuQ2hhcmdlKSlgIHLDs8W8bnljaCB3em9yw7N3IGNoZW1pY3pueWNoIG1hdGVyaWHFgsOzdyBiYXRlcmlpIHcgc3RhbmllIG5hxYJhZG93YW55bS4gTmFqbGljem5pZWpzenltaSBzxIUgTW5PMiwgVGlPMiwgVm8yLCBDck8yLCBOaU8yLCBGZU8yLg0KDQotLS0tLS0tLS0tLS0tLQ0KDQpgYGB7ciBmb3JtdWxhLWRpc2NoYXJnZS1zdW1tYXJ5LCBmaWcud2lkdGg9MTYsIGZpZy5oZWlnaHQ9OH0NCg0KZm9ybXVsYV9kaXNjaGFyZ2Vfc3VtbWFyeSA8LSBkYXRhICU+JQ0KICBncm91cF9ieShGb3JtdWxhLkRpc2NoYXJnZSkgJT4lDQogIHN1bW1hcmlzZSh0b3RhbCA9IG4oKSkgJT4lDQogIGFycmFuZ2UoZGVzYyh0b3RhbCkpDQoNCmRpc2NoYXJnZV9wZXJjZW50aWxlXzk5IDwtIHF1YW50aWxlKHNlbGVjdChmb3JtdWxhX2Rpc2NoYXJnZV9zdW1tYXJ5LCB0b3RhbCksIHByb2JzID0gMC45OSwgbmEucm0gPSBUUlVFKQ0KZm9ybXVsYV9kaXNjaGFyZ2VfdmFsdWVzXzk5X3BlcmNlbnRpbGUgPC0gZm9ybXVsYV9kaXNjaGFyZ2Vfc3VtbWFyeSAlPiUNCiAgZmlsdGVyKHRvdGFsID49IGRpc2NoYXJnZV9wZXJjZW50aWxlXzk5KQ0KDQpmb3JtdWxhX2Rpc2NoYXJnZV92YWx1ZXNfOTlfcGVyY2VudGlsZQ0KDQpmb3JtdWxhX2Rpc2NoYXJnZV92YWx1ZXNfOTlfcGVyY2VudGlsZSAlPiUNCiAgZ2dwbG90KCkgKw0KICAgbGFicyh0aXRsZSA9IHBhc3RlKCJXesOzcnkgY2hlbWljem5lIG1hdGVyaWHFgnUgYmF0ZXJpaSB3IHN0YW5pZSByb3rFgmFkb3dhbnltIiksDQogICAgICAgICAgIHggPSAiV3rDs3IgdyBzdGFuaWUgcm96xYJhZG93YW55bSIsDQogICAgICAgICAgIHkgPSAiTGljemJhIG9zZXJ3YWNqaSIpICsNCiAgICAgIGdlb21fYmFyKGFlcyh4ID0gcmVvcmRlcihGb3JtdWxhLkRpc2NoYXJnZSwgdG90YWwpLCB5ID0gdG90YWwsIGZpbGwgPSBGb3JtdWxhLkRpc2NoYXJnZSksIHN0YXQgPSAiaWRlbnRpdHkiLCAgd2lkdGggPSAwLjUpICsNCiAgICAgIHRoZW1lKA0KICAgICAgICB0ZXh0ID0gZWxlbWVudF90ZXh0KHNpemUgPSAxMiksDQogICAgICAgIGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gOTAsIGhqdXN0ID0gMSwgc2l6ZSA9IDgpLA0KICAgICAgICBwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemUgPSAzMCkNCiAgICAgICkNCg0KYGBgDQoNCld5a3JlcyBwcnplZHN0YXdpYSBsaWN6YsSZIHd5c3TEhXBpZcWEIHLDs8W8bnljaCB3em9yw7N3IGNoZW1pY3pueWNoIG1hdGVyaWHFgsOzdyBiYXRlcmlpIHcgc3RhbmllIHJvesWCYWRvd2FueW0uIFcgemJpb3J6ZSBqZXN0IGByIGxlbmd0aCh1bmlxdWUoZGF0YSRGb3JtdWxhLkRpc2NoYXJnZSkpYCByw7PFvG55Y2ggd3pvcsOzdyBjaGVtaWN6bnljaCBtYXRlcmlhxYLDs3cgYmF0ZXJpaSB3IHN0YW5pZSByb3rFgmFkb3dhbnltLiBOYWpjesSZxZtjaWVqIHd5c3TEmXB1asSFY2Ugd3pvcnkgdG8gTGlWT0YxMSwgTGkyTzVGNSwgTGlGZVBPNCwgTGlDb1BPNC4gWm5hY3puYSB3acSZa3N6b8WbxIcgbmFqY3rEmcWbY2llaiB3eXN0xJlwdWrEhWN5Y2ggd3pvcsOzdyB6YXdpZXJhIGN6xIVzdGVjemvEmSBsaXR1Lg0KDQoNCiMjIEtvcmVsYWNqYSB6bWllbm55Y2gNCg0KUG9uacW8c3phIG1hY2llcnoga29yZWxhY2ppIGlsdXN0cnVqZSB3c3DDs8WCY3p5bm5pa2kga29yZWxhY2ppIFBlYXJzb25hIGRsYSB3eWJyYW55Y2ggYXRyeWJ1dMOzdy4gS29sb3J5IGthZmVsa8OzdyByZXByZXplbnR1asSFIHNpxYLEmSBvcmF6IGtpZXJ1bmVrIGtvcmVsYWNqaS4gT2RjaWVuaWUgbmllYmllc2tpZWdvIHdza2F6dWrEhSBuYSBkb2RhdG5pxIUga29yZWxhY2rEmSwgYSBvZGNpZW5pZSBjemVyd29uZWdvIG5hIHVqZW1uxIUuDQoNCmBgYHtyIGNvb3JlbGF0aW9uLW1hdHJpeCwgZWNobz1GQUxTRSwgIGZpZy53aWR0aD0xNiwgZmlnLmhlaWdodD04fQ0KbnVtYmVyX2F0dHJfZGF0YSA8LSBzZWxlY3QoZGF0YSwgKE1heC5EZWx0YS5Wb2x1bWU6TWF4LlZvbHRhZ2UuU3RlcCkpDQoNCmNvcl9tYXRyaXggPC0gY29yKG51bWJlcl9hdHRyX2RhdGEsIG1ldGhvZCA9ICJwZWFyc29uIikNCg0KY29ycnBsb3QubWl4ZWQoY29yX21hdHJpeCwNCiAgdGwucG9zID0gJ2x0JywNCiAgb3JkZXIgPSAnQU9FJywNCiAgbG93ZXIgPSAnc2hhZGUnLA0KICB1cHBlciA9ICdudW1iZXInDQopDQpgYGANCg0KKipOYWp3ecW8c3p5IHdzcG9sY3p5bm5payBrb3JlbGFjamkqKiB3eXN0ZXB1amUgcG9taWVkenkgcGFyYW1pIGF0cnlidXTDs3c6XA0KLSAqKkdyYXZpbWV0cmljIEVuZXJneSBpIFZvbHVtZXRyaWMgRW5lcmd5KiogLSAwLjkzIFwNCi0gKipHcmF2aW1ldHJpYyBDYXBjaXR5IGkgVm9sdW1ldHJpYyBDYXBhY2l0eSoqIC0gMC44NiBcDQotICoqU3RhYmlsaXR5IENoYXJnZSBpIFN0YWJpbGl0eSBEaXNjaGFyZ2UqKiAtIDAuODAgXA0KLSBHcmF2aW1ldHJpYyBDYXBhY2l0eSBpIEF0b21pYyBGcmFjdGlvbiBEaXNjaGFyZ2UgLSAwLjY4IFwNCi0gQXZlcmFnZSBWb2x0YWdlIGkgR3JhdmltZXRyaWMgRW5lcmd5IC0gMC42Nw0KDQojIyMgS29yZWxhY2phIHBvbWnEmWR6eSBlbmVyZ2nEhSBncmF3aW1ldHJ5Y3puxIUgaSB3b2x1bWV0cnljem7EhQ0KDQpgYGB7ciB9DQpncmF2aW1ldHJpY192b2x1bWV0cmljX2VuZXJneV9jb3JyZWxhdGlvbiA8LSBjb3IoZGF0YSRHcmF2aW1ldHJpYy5FbmVyZ3ksIGRhdGEkVm9sdW1ldHJpYy5FbmVyZ3ksIHVzZSA9ICJjb21wbGV0ZS5vYnMiKQ0KDQpnZ3Bsb3QoZGF0YSwgYWVzKHggPSBHcmF2aW1ldHJpYy5FbmVyZ3ksIHkgPSBWb2x1bWV0cmljLkVuZXJneSkpICsNCiAgZ2VvbV9wb2ludChjb2xvciA9ICJkYXJrZ3JlZW4iLCBzaXplID0gMiwgYWxwaGEgPSAwLjcpICsNCiAgZ2VvbV9zbW9vdGgobWV0aG9kID0gImxtIiwgY29sb3IgPSAiYmx1ZSIsIHNlID0gRkFMU0UsIGxpbmV0eXBlID0gImRhc2hlZCIpICsNCiAgZ2VvbV9zbW9vdGgobWV0aG9kID0gImxvZXNzIiwgY29sb3IgPSAicmVkIiwgc2UgPSBUUlVFLCBmaWxsID0gImdyYXk4MCIpICsNCiAgbGFicyh0aXRsZSA9ICJLb3JlbGFjamEgbWnEmWR6eSBncmF3aW1ldHJ5Y3puxIUgaSB3b2x1bWV0cnljem7EhSBnxJlzdG/Fm2NpxIUgZW5lcmdpaSIsDQogICAgICAgc3VidGl0bGUgPSBwYXN0ZSgiV3Nww7PFgmN6eW5uaWsga29yZWxhY2ppID0iLCByb3VuZChncmF2aW1ldHJpY192b2x1bWV0cmljX2VuZXJneV9jb3JyZWxhdGlvbiwgMikpLA0KICAgICAgIHggPSAiR3Jhd2ltZXRyeWN6bmEgZ8SZc3RvxZvEhyBlbmVyZ2lpIChXaC9rZykiLA0KICAgICAgIHkgPSAiV29sdW1ldHJ5Y3puYSBnxJlzdG/Fm8SHIGVuZXJnaWkgKFdoL0wpIikgKw0KICB0aGVtZV9taW5pbWFsKCkNCmBgYA0KV3lrcmVzIHByemVkc3Rhd2lhICoqemFsZcW8bm/Fm8SHIG1pxJlkenkgZ8SZc3RvxZtjacSFIGVuZXJnaWkgd29sdW1ldHJ5Y3puxIUqKiAoV2gvTCwgZW5lcmdpYSBuYSBqZWRub3N0a8SZIG9iasSZdG/Fm2NpKSAqKmEgZ3Jhd2ltZXRyeWN6bsSFKiogKFdoL2tnLCBlbmVyZ2lhIG5hIGplZG5vc3RrxJkgbWFzeSksIGdkemllIHdpZG9jem5hIGplc3QgKipzaWxuYSBrb3JlbGFjamEqKiBkb2RhdG5pYSBtacSZZHp5IHR5bWkgcGFyYW1ldHJhbWkuIEfEmXN0b8WbxIcgZW5lcmdpaSBqZXN0ICoqa2x1Y3pvd3ltIHdza2HFum5pa2llbSB3eWRham5vxZtjaSBiYXRlcmlpKiogLSBpbSB3ecW8c3phIHdhcnRvxZvEhywgdHltIHdpxJljZWogZW5lcmdpaSBtb8W8ZSBiecSHIHptYWdhenlub3dhbmUgdyBkYW5laiBvYmrEmXRvxZtjaSBsdWIgbWFzaWUgYmF0ZXJpaSwgY28gamVzdCBzemN6ZWfDs2xuaWUgaXN0b3RuZSB3IHphc3Rvc293YW5pYWNoIG1vYmlsbnljaCwgdGFraWNoIGphayBwb2phemR5IGVsZWt0cnljem5lIGN6eSB1cnrEhWR6ZW5pYSBwcnplbm/Fm25lLiAqKldpxJlrc3pvxZvEhyBiYWRhbnljaCBtYXRlcmlhxYLDs3cgc2t1cGlhIHNpxJkgdyB6YWtyZXNpZSBkbyAyMDAwIFdoL2tnIGkgNzUwMCBXaC9MKiosIGNob8SHIHd5c3TEmXB1amUga2lsa2Egb2JpZWN1asSFY3ljaCB3eWrEhXRrw7N3IG8gd3nFvHN6eWNoIHBhcmFtZXRyYWNoLCBrdMOzcmUgbW9nxIUgc3Rhbm93acSHIHBvdGVuY2phbG5lIGtpZXJ1bmtpIHJvendvanUgbm93eWNoLCB3eWRham5pZWpzenljaCBiYXRlcmlpLg0KDQoNCiMjIyBLb3JlbGFjamEgcG9tacSZZHp5IHBvamVtbm/Fm2NpxIUgZ3Jhd2ltZXRyeWN6bsSFIGkgd29sdW1ldHJ5Y3puxIUNCg0KYGBge3J9DQpncmF2aW1ldHJpY192b2x1bWV0cmljX2NhcGFjaXR5X2NvcnJlbGF0aW9uIDwtIGNvcihkYXRhJEdyYXZpbWV0cmljLkNhcGFjaXR5LCBkYXRhJFZvbHVtZXRyaWMuQ2FwYWNpdHksIHVzZSA9ICJjb21wbGV0ZS5vYnMiKQ0KDQpnZ3Bsb3QoZGF0YSwgYWVzKHggPSBHcmF2aW1ldHJpYy5DYXBhY2l0eSwgeSA9IFZvbHVtZXRyaWMuQ2FwYWNpdHkpKSArDQogIGdlb21fcG9pbnQoY29sb3IgPSAiZGFya2dyZWVuIiwgc2l6ZSA9IDIsIGFscGhhID0gMC43KSArDQogIGdlb21fc21vb3RoKG1ldGhvZCA9ICJsbSIsIGNvbG9yID0gImJsdWUiLCBzZSA9IEZBTFNFKSArDQogIGdlb21fc21vb3RoKG1ldGhvZCA9ICJsb2VzcyIsIGNvbG9yID0gInJlZCIsIHNlID0gVFJVRSwgZmlsbCA9ICJncmF5ODAiKSArDQogIGxhYnModGl0bGUgPSAiS29yZWxhY2phIG1pxJlkenkgZ3Jhd2ltZXRyeWN6bsSFIGkgd29sdW1ldHJ5Y3puxIUgcG9qZW1ub8WbY2nEhSAiLA0KICAgICAgIHN1YnRpdGxlID0gcGFzdGUoIkNvcnJlbGF0aW9uID0iLCByb3VuZChncmF2aW1ldHJpY192b2x1bWV0cmljX2NhcGFjaXR5X2NvcnJlbGF0aW9uLCAyKSksDQogICAgICAgeCA9ICJQb2plbW5vxZvEhyBncmF3aW1ldHJ5Y3puYSAobUFoL2cpIiwNCiAgICAgICB5ID0gIlBvamVtbm/Fm8SHIHdvbHVtZXRyeWN6bmEgKG1BaC9jbcKzKSIpICsNCiAgdGhlbWVfbWluaW1hbCgpDQoNCmBgYA0KDQpXeWtyZXMgcHJ6ZWRzdGF3aWEgKip6YWxlxbxub8WbxIcgbWnEmWR6eSBwb2plbW5vxZtjacSFIHdvbHVtZXRyeWN6bsSFKiogKG1BaC9jbcKzLCBpbG/Fm8SHIMWCYWR1bmt1IG5hIGplZG5vc3RrxJkgb2JqxJl0b8WbY2kpICoqYSBncmF3aW1ldHJ5Y3puxIUqKiAobUFoL2csIGlsb8WbxIcgxYJhZHVua3UgbmEgamVkbm9zdGvEmSBtYXN5KSBtYXRlcmlhxYLDs3csIGdkemllIHBvamVtbm/Fm8SHIGdyYXdpbWV0cnljem5hIG9rcmXFm2xhIGlsZSBlbmVyZ2lpIG1vxbxuYSB6bWFnYXp5bm93YcSHIHcgZGFuZWogbWFzaWUgbWF0ZXJpYcWCdSwgYSB3b2x1bWV0cnljem5hIC0gaWxlIHcgZGFuZWogb2JqxJl0b8WbY2ksIGNvIG1hIGtsdWN6b3dlIHpuYWN6ZW5pZSBwcnp5IHByb2pla3Rvd2FuaXUgYmF0ZXJpaSBvIHLDs8W8bnltIHByemV6bmFjemVuaXUuICoqV3Nww7PFgmN6eW5uaWsga29yZWxhY2ppIDAuODYgd3NrYXp1amUgbmEgc2lsbsSFIHphbGXFvG5vxZvEhyBtacSZZHp5IHR5bWkgcGFyYW1ldHJhbWkqKiwgY2hvxIcgbmllIHRhayBzaWxuxIUgamFrIHcgcHJ6eXBhZGt1IGfEmXN0b8WbY2kgZW5lcmdpaS4gTmEgcHJ6eWvFgmFkLCBtYXRlcmlhxYIgbyB3eXNva2llaiBwb2plbW5vxZtjaSBncmF3aW1ldHJ5Y3puZWogbW/FvGUgYnnEhyBsZWtraSwgYWxlIHpham1vd2HEhyBkdcW8byBtaWVqc2NhLCBwb2RjemFzIGdkeSBtYXRlcmlhxYIgbyB3eXNva2llaiBwb2plbW5vxZtjaSB3b2x1bWV0cnljem5laiBtb8W8ZSBiecSHIGNpxJnFvHN6eSwgYWxlIGJhcmR6aWVqIGtvbXBha3Rvd3kgW0BvZ25pd2EtbGl0b3dvLWpvbm93ZV0uDQoNCg0KIyMjIEtvcmVsYWNqYSBwb21pxJlkenkgc3RhYmlsbm/Fm2NpxIUgbWF0ZXJpYcWCdSB3IHN0YW5pZSBuYcWCYWRvd2FueW0gaSByb3rFgmFkb3dhbnltDQoNCmBgYHtyfQ0Kc3RhYmlsaXR5X2NoYXJnZV9kaXNjaGFyZ2VfY29vcmVsYXRpb24gPC0gY29yKGRhdGEkU3RhYmlsaXR5LkNoYXJnZSwgZGF0YSRTdGFiaWxpdHkuRGlzY2hhcmdlLCB1c2UgPSAiY29tcGxldGUub2JzIikNCg0KZ2dwbG90KGRhdGEsIGFlcyh4ID0gU3RhYmlsaXR5LkNoYXJnZSwgeSA9IFN0YWJpbGl0eS5EaXNjaGFyZ2UpKSArDQogIGdlb21fcG9pbnQoY29sb3IgPSAiZGFya2dyZWVuIiwgc2l6ZSA9IDIsIGFscGhhID0gMC43KSArDQogIGdlb21fc21vb3RoKG1ldGhvZCA9ICJsbSIsIGNvbG9yID0gImJsdWUiLCBzZSA9IEZBTFNFLCBsaW5ldHlwZSA9ICJkYXNoZWQiKSArDQogIGdlb21fc21vb3RoKG1ldGhvZCA9ICJsb2VzcyIsIGNvbG9yID0gInJlZCIsIHNlID0gVFJVRSwgZmlsbCA9ICJncmF5ODAiKSArDQogIGxhYnModGl0bGUgPSAiU3RhYmlsaXR5IENoYXJnZSB2cyBTdGFiaWxpdHkgRGlzY2hhcmdlIiwNCiAgICAgICBzdWJ0aXRsZSA9IHBhc3RlKCJDb3JyZWxhdGlvbiA9Iiwgcm91bmQoc3RhYmlsaXR5X2NoYXJnZV9kaXNjaGFyZ2VfY29vcmVsYXRpb24sIDIpKSwNCiAgICAgICB4ID0gIlN0YWJpbGl0eSBDaGFyZ2UiLA0KICAgICAgIHkgPSAiU3RhYmlsaXR5IERpc2NoYXJnZSIpICsNCiAgdGhlbWVfbWluaW1hbCgpDQoNCmBgYA0KDQpXeWtyZXMgcHJ6ZWRzdGF3aWEgKip6YWxlxbxub8WbxIcgbWnEmWR6eSBzdGFiaWxub8WbY2nEhSBtYXRlcmlhxYJ1IHcgc3RhbmllIG5hxYJhZG93YW55bSoqIChTdGFiaWxpdHkgQ2hhcmdlKSAqKmEgc3RhYmlsbm/Fm2NpxIUgdyBzdGFuaWUgcm96xYJhZG93YW55bSoqIChTdGFiaWxpdHkgRGlzY2hhcmdlKSwgemUgd3Nww7PFgmN6eW5uaWtpZW0ga29yZWxhY2ppIDAuOCB3c2thenVqxIVjeW0gbmEgc2lsbsSFIGRvZGF0bmnEhSB6YWxlxbxub8WbxIcuIFN0YWJpbG5vxZvEhyBtYXRlcmlhxYJ1IGplc3QgKiprbHVjem93eW0gcGFyYW1ldHJlbSBva3JlxZtsYWrEhWN5bSwgamFrIGRvYnJ6ZSBtYXRlcmlhxYIgemFjaG93dWplIHN3b2rEhSBzdHJ1a3R1csSZIGkgd8WCYcWbY2l3b8WbY2kgcG9kY3phcyBjeWtsaSDFgmFkb3dhbmlhIGkgcm96xYJhZG93YW5pYSoqIC0gaW0gbmnFvHN6YSB3YXJ0b8WbxIcsIHR5bSBtYXRlcmlhxYIgamVzdCBiYXJkemllaiBzdGFiaWxueSBpIGJlenBpZWN6bnkgdyB1xbx5dGtvd2FuaXUuIFdpxJlrc3pvxZvEhyBiYWRhbnljaCBtYXRlcmlhxYLDs3cgc2t1cGlhIHNpxJkgdyB6YWtyZXNpZSBuaXNraWNoIHdhcnRvxZtjaSAoMC0yKSBkbGEgb2J1IHBhcmFtZXRyw7N3LCBjbyBqZXN0IHBvxbzEhWRhbmUsIG5hdG9taWFzdCBwdW5rdHkgb2RzdGFqxIVjZSBvIHd5xbxzenljaCB3YXJ0b8WbY2lhY2ggKHBvd3nFvGVqIDQpIG1vZ8SFIHdza2F6eXdhxIcgbmEgbWF0ZXJpYcWCeSBwcm9ibGVtYXR5Y3puZSwga3TDs3JlIG1vZ8SFIGJ5xIcgbW5pZWogb2Rwb3dpZWRuaWUgZG8gemFzdG9zb3dhxYQgdyBiYXRlcmlhY2ggemUgd3pnbMSZZHUgbmEgcG90ZW5jamFsbsSFIG5pZXN0YWJpbG5vxZvEhy4NCg0KIyMjIEtvcmVsYWNqYSBwb21pxJlkenkgcG9qZW1ub8WbY2nEhSBncmF3aW1ldHJ5Y3puxIUgaSB1ZHppYcWCIGF0b21vd3ltIHNrxYJhZG5pa8OzdyB3IHN0YW5pZSByb3rFgmFkb3dhbnltDQoNCmBgYHtyIGNvb3JlbGF0aW9uLWdyYXZpbWV0cmljLWNhcGFjaXR5LWF0b21pYy1ncmFjdGlvbi1kaXNjaGFyZ2V9DQpncmF2aW1ldHJpY19jYXBhY2l0eV9hdG9taWNfZnJhY3Rpb25fZGlzY2hhcmdlX2Nvb3JlbGF0aW9uIDwtIGNvcihkYXRhJEdyYXZpbWV0cmljLkNhcGFjaXR5LCBkYXRhJEF0b21pYy5GcmFjdGlvbi5EaXNjaGFyZ2UsIHVzZSA9ICJjb21wbGV0ZS5vYnMiKQ0KDQpnZ3Bsb3QoZGF0YSwgYWVzKHggPSBHcmF2aW1ldHJpYy5DYXBhY2l0eSwgeSA9IEF0b21pYy5GcmFjdGlvbi5EaXNjaGFyZ2UpKSArDQogIGdlb21fcG9pbnQoYWVzKGNvbG9yID0gQXRvbWljLkZyYWN0aW9uLkRpc2NoYXJnZSksIHNpemUgPSAzLCBhbHBoYSA9IDAuNykgKw0KICBnZW9tX3Ntb290aChtZXRob2QgPSAibG9lc3MiLCBjb2xvciA9ICJyZWQiLCBzZSA9IFRSVUUsIGZpbGwgPSAiZ3JheTgwIikgKw0KICBsYWJzKHRpdGxlID0gIktvcmVsYWNqYSBtacSZZHp5IHBvamVtbm5vxZtjacSFIGdyYXdpbWV0cnljem7EhSBhIHVkemlhxYIgYXRvbW93eW0gc2vFgmFkbmlrw7N3IHcgc3RhbmllIHJvesWCYWRvd2FueW0iLA0KICAgICAgIHN1YnRpdGxlID0gcGFzdGUoIkNvcnJlbGF0aW9uID0iLCByb3VuZChncmF2aW1ldHJpY19jYXBhY2l0eV9hdG9taWNfZnJhY3Rpb25fZGlzY2hhcmdlX2Nvb3JlbGF0aW9uLCAyKSksDQogICAgICAgeCA9ICJQb2plbW5vxZvEhyBncmF3aW1ldHJ5Y3puYSAobUFoL2cpIiwNCiAgICAgICB5ID0gIlVkemlhxYIgYXRvbW93eSBza8WCYWRuaWvDs3cgdyBzdGFuaWUgcm96xYJhZG93YW55bS4iKSArDQogIHNjYWxlX2NvbG9yX2dyYWRpZW50KGxvdyA9ICJvcmFuZ2UiLCBoaWdoID0gInB1cnBsZSIpICsNCiAgdGhlbWVfbWluaW1hbCgpDQoNCmBgYA0KDQpXeWtyZXMgcHJ6ZWRzdGF3aWEgKip6YWxlxbxub8WbxIcgbWnEmWR6eSBwb2plbW5vxZtjacSFIGdyYXdpbWV0cnljem7EhSoqIChHcmF2aW1ldHJpYyBDYXBhY2l0eSwgbUFoL2cpICoqYSB1ZHppYcWCZW0gYXRvbW93eW0gdyBzdGFuaWUgcm96xYJhZG93YW5pYSoqIChBdG9taWMgRnJhY3Rpb24gRGlzY2hhcmdlKS4gTW/FvG5hIHphb2JzZXJ3b3dhxIcgdW1pYXJrb3dhbmllIHNpbG7EhSBkb2RhdG5pxIUgemFsZcW8bm/Fm8SHLCBjbyBwb3R3aWVyZHphIHdzcMOzxYJjenlubmlrIGtvcmVsYWNqaSB3eW5vc3rEhWN5IDAuNjguIFcgbWlhcsSZIHd6cm9zdHUgcG9qZW1ub8WbY2kgZ3Jhd2ltZXRyeWN6bmVqLCB1ZHppYcWCIGF0b21vd3kgdyBzdGFuaWUgcm96xYJhZG93YW5pYSB6d2nEmWtzemEgc2nEmSwgb3NpxIVnYWrEhWMgd2FydG/Fm8SHIG1ha3N5bWFsbsSFIGJsaXNrxIUgMS4wLiBcDQpLb2xvciBwdW5rdMOzdyByZXByZXplbnR1amUgd2FydG/Fm8SHIEF0b21pYyBGcmFjdGlvbiBEaXNjaGFyZ2UsIGdkemllIGphxZtuaWVqc3plIGtvbG9yeSB3c2thenVqxIUgbmEgbmnFvHN6ZSB3YXJ0b8WbY2ksIGEgY2llbW5pZWpzemUgbmEgd3nFvHN6ZS4gRGFuZSB3c2thenVqxIUsIMW8ZSB3acSZa3N6b8WbxIcgb2JzZXJ3YWNqaSB6bmFqZHVqZSBzacSZIHcgemFrcmVzaWUgbmlza2llaiBwb2plbW5vxZtjaSBncmF3aW1ldHJ5Y3puZWogKDwxMDAwIG1BaC9nKSwgYSBkbGEgd2FydG/Fm2NpIHBvd3nFvGVqIDIwMDAgbUFoL2cgemFsZcW8bm/Fm8SHIHN0YWplIHNpxJkgbmllbGluaW93YS4gU3VnZXJ1amUgdG8sIMW8ZSBtYXRlcmlhxYJ5IG8gd3nFvHN6ZWogcG9qZW1ub8WbY2kgZ3Jhd2ltZXRyeWN6bmVqIG1hasSFIHRlbmRlbmNqxJkgZG8gb3NpxIVnYW5pYSB3ecW8c3p5Y2ggdWR6aWHFgsOzdyBhdG9tb3d5Y2ggdyBzdGFuaWUgcm96xYJhZG93YW5pYS4NCg0KIyMjIEtvcmVsYWNqYSBwb21pxJlkenkgxZtyZWRuaW0gbmFwacSZY2llbSBhIGVuZXJnacSFIGdyYXdpbWV0cnljem7EhQ0KDQpgYGB7cn0NCmZpbHRlcmVkRGF0YSA8LSBkYXRhICU+JWZpbHRlcihkYXRhJFN0ZXBzID09IDMpDQpjb3JyZWxhdGlvbiA8LSBjb3IoZGF0YSRBdmVyYWdlLlZvbHRhZ2UsIGRhdGEkR3JhdmltZXRyaWMuRW5lcmd5LCB1c2UgPSAiY29tcGxldGUub2JzIikNCg0KZ2dwbG90KGRhdGEsIGFlcyh4ID0gQXZlcmFnZS5Wb2x0YWdlLCB5ID0gR3JhdmltZXRyaWMuRW5lcmd5KSkgKw0KICBnZW9tX3BvaW50KGNvbG9yID0gImRhcmtibHVlIiwgc2l6ZSA9IDMsIGFscGhhID0gMC43KSArDQogIGdlb21fc21vb3RoKG1ldGhvZCA9ICJsbSIsIGNvbG9yID0gImRhcmtyZWQiLCBzZSA9IEZBTFNFLCBsaW5ldHlwZSA9ICJkYXNoZWQiKSArDQogIGxhYnModGl0bGUgPSAiQXZlcmFnZSBWb2x0YWdlIHZzIEdyYXZpbWV0cmljIEVuZXJneSIsDQogICAgICAgc3VidGl0bGUgPSBwYXN0ZSgiQ29ycmVsYXRpb24gPSIsIHJvdW5kKGNvcnJlbGF0aW9uLCAyKSksDQogICAgICAgeCA9ICJBdmVyYWdlIFZvbHRhZ2UgKFYpIiwNCiAgICAgICB5ID0gIkdyYXZpbWV0cmljIEVuZXJneSBEZW5zaXR5IChXaC9rZykiKSArDQogIHRoZW1lX2NsYXNzaWMoKQ0KDQpgYGANCg0KDQpgYGB7ciBhdmVyYWdlLXZvbHRhZ2UtZ3JhdmltZXRyaWMtZW5lcmd5LWJ5LXN0ZXAsIGVjaG89RkFMU0UsIGZpZy53aWR0aD0xMiwgZmlnLmhlaWdodD0xMH0NCg0KZGF0YV93aXRoX2NvciA8LSBkYXRhICU+JQ0KICBncm91cF9ieShTdGVwcykgJT4lDQogIHN1bW1hcmlzZSgNCiAgICBjb3JyZWxhdGlvbiA9IGNvcihBdmVyYWdlLlZvbHRhZ2UsIEdyYXZpbWV0cmljLkVuZXJneSwgdXNlID0gImNvbXBsZXRlLm9icyIpLA0KICAgIG5fY2FzZXMgPSBuKCkgDQogICkNCg0KcCA8LSBnZ3Bsb3QoZGF0YSwgYWVzKHggPSBBdmVyYWdlLlZvbHRhZ2UsIHkgPSBHcmF2aW1ldHJpYy5FbmVyZ3kpKSArDQogICBnZW9tX3BvaW50KGFlcyh0ZXh0ID0gcGFzdGUoIlN0ZXA6IiwgU3RlcHMsIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIjxicj5Wb2x0YWdlOiIsIEF2ZXJhZ2UuVm9sdGFnZSwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiPGJyPkVuZXJneToiLCBHcmF2aW1ldHJpYy5FbmVyZ3ksIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIjxicj5Jb246IiwgV29ya2luZy5Jb24pKSwgDQogICAgICAgICAgICAgY29sb3IgPSAiZGFya2JsdWUiLCBzaXplID0gMywgYWxwaGEgPSAwLjcpICsNCiAgZ2VvbV9zbW9vdGgobWV0aG9kID0gImxtIiwgY29sb3IgPSAiZGFya3JlZCIsIHNlID0gRkFMU0UsIGxpbmV0eXBlID0gImRhc2hlZCIpICsNCiAgZmFjZXRfd3JhcCh+IFN0ZXBzLCBzY2FsZXMgPSAiZnJlZSIsICAgbmNvbCA9IDIsIA0KICAgICAgICAgICAgIGxhYmVsbGVyID0gbGFiZWxsZXIoU3RlcHMgPSBmdW5jdGlvbih4KSB7DQogICAgICAgICAgICAgIHJvdyA8LSBkYXRhX3dpdGhfY29yW2RhdGFfd2l0aF9jb3IkU3RlcHMgPT0geCwgXQ0KICAgICAgICAgICAgICBwYXN0ZTAoIlN0ZXAgPSAiLCB4LCAiIChDb3JyID0gIiwgcm91bmQocm93JGNvcnJlbGF0aW9uLCAyKSwgDQogICAgICAgICAgICAgICAgICAgICAgIiwgbiA9ICIsIHJvdyRuX2Nhc2VzLCAiKSIpDQogICAgICAgICAgICAgfSkpICsNCiAgIGxhYnModGl0bGUgPSAixZpyZWRuaWUgbmFwacSZY2llIGEgRW5lcmdpYSBncmF3aW1ldHJ5Y3puYSBwcnp5IHV3emdsxJlkbmllbml1IHdhcnRvxZtjaSBrcm9rdSIsDQogICAgICAgeCA9ICJBdmVyYWdlIFZvbHRhZ2UgKFYpIiwNCiAgICAgICB5ID0gIkdyYXZpbWV0cmljIEVuZXJneSBEZW5zaXR5IChXaC9rZykiKSAgKw0KICB0aGVtZV9ncmV5KCkgKw0KICAgdGhlbWUoDQogICAgcGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChtYXJnaW4gPSBtYXJnaW4oYiA9IDIwKSksDQogICAgcGxvdC5tYXJnaW4gPSBtYXJnaW4odCA9IDIwLCByID0gMjAsIGIgPSAyMCwgbCA9IDIwKQ0KICApDQoNCmdncGxvdGx5KHAsICB0b29sdGlwID0gInRleHQiKQ0KYGBgDQoNCld5a3Jlc3kgcHJ6ZWRzdGF3aWFqxIUgemFsZcW8bm/Fm2NpIG1pxJlkenkgxZtyZWRuaW0gbmFwacSZY2llbSAoQXZlcmFnZSBWb2x0YWdlLCBWKSBhIGfEmXN0b8WbY2nEhSBlbmVyZ2lpIGdyYXdpbWV0cnljem5laiAoR3JhdmltZXRyaWMgRW5lcmd5IERlbnNpdHksIFdoL2tnKSBkbGEgcsOzxbxueWNoIHdhcnRvxZtjaSBrcm9rdSBuYXBpxJljaWEuDQpEYW5lIHdza2F6dWrEhSwgxbxlIHdyYXogemUgd3pyb3N0ZW0gxZtyZWRuaWVnbyBuYXBpxJljaWEgendpxJlrc3phIHNpxJkgZ8SZc3RvxZvEhyBlbmVyZ2lpIGdyYXdpbWV0cnljem5lai4gV2nEmWtzem/Fm8SHIGRhbnljaCBza3VwaWEgc2nEmSB3IHpha3Jlc2llIG5pc2tpY2ggd2FydG/Fm2NpIG5hcGnEmWNpYSAoPDEwIFYpLCBjbyBzdWdlcnVqZSwgxbxlIG1hdGVyaWHFgnkgbyB3ecW8c3p5bSBuYXBpxJljaXUgc8SFIG1uaWVqIGxpY3puZSwgYWxlIHd5a2F6dWrEhSB3acSZa3N6xIUgZWZla3R5d25vxZvEhyBlbmVyZ2V0eWN6bsSFLg0KDQoNCiMjIEFuYWxpemEgd8WCYcWbY2l3b8WbY2kNCg0KIyMjIFN0YWJpbG5vxZvEhyB3IHN0YW5pZSBuYcWCYWRvd2FueW0gaSByb3rFgmFkb3dhbnltDQoNCioqU3RhYmlsaXR5IENoYXJnZSoqDQoNCi0gT2tyZcWbbGEgc3RhYmlsbm/Fm8SHIG1hdGVyaWHFgnUgdyBiYXRlcmlpLCBnZHkgamVzdCB3IHBlxYJuaSBuYcWCYWRvd2FueQ0KLSBXecW8c3phIHN0YWJpbG5vxZvEhyBvem5hY3phLCDFvGUgbWF0ZXJpYcWCIGLEmWR6aWUgbW5pZWogcG9kYXRueSBuYSB1c3prb2R6ZW5pYSBsdWIgZGVncmFkYWNqxJkgcG9kY3phcyDFgmFkb3dhbmlhLiBKZXN0IHRvIGlzdG90bmUsIGFieSB6YXBld25pxIcgZMWCdWdvdHJ3YcWCZSBkemlhxYJhbmllIGJhdGVyaWkgYmV6IHV0cmF0eSBqZWogd8WCYcWbY2l3b8WbY2kuDQoNCioqU3RhYmlsaXR5IERpc2NoYXJnZSoqDQoNCi0gT2tyZcWbbGEgc3RhYmlsbm/Fm8SHIG1hdGVyaWHFgnUgdyBiYXRlcmlpLCBnZHkgamVzdCB3IHBlxYJuaSByb3rFgmFkb3dhbnkuDQotIFN0YWJpbG5vxZvEhyB3IHN0YW5pZSByb3rFgmFkb3dhbnltIGplc3Qga2x1Y3pvd2EgZGxhIHV0cnp5bWFuaWEgZWZla3R5d25vxZtjaSBiYXRlcmlpIHByemV6IHdpZWxlIGN5a2xpIMWCYWRvd2FuaWEgaSByb3rFgmFkb3dhbmlhLiBaYXBld25pYSBvbmEsIMW8ZSBtYXRlcmlhxYIgbmllIHVsZWduaWUgZGVncmFkYWNqaSwgY28gbW9nxYJvYnkgcHJvd2FkemnEhyBkbyB6bW5pZWpzemVuaWEgcG9qZW1ub8WbY2kgaSDFvHl3b3Rub8WbY2kgYmF0ZXJpaS4NCg0KDQpgYGB7cn0NCnN1bW1hcnlfc3RhYmlsaXR5X2NoYXJnZV93b3JraW5nX2lvbiA8LSBkYXRhICU+JQ0KICBncm91cF9ieShXb3JraW5nLklvbikgJT4lDQogIHN1bW1hcmlzZShzdGFiaWxpdHlfY2hhcmdlX21lYW4gPSBtZWFuKFN0YWJpbGl0eS5DaGFyZ2UpLA0KICAgICAgICAgICAgc3RhYmlsaXR5X2NoYXJnZV9tZWRpYW4gPSBtZWRpYW4oU3RhYmlsaXR5LkNoYXJnZSksDQogICAgICAgICAgICBzdGFiaWxpdHlfY2hhcmdlX21pbiA9IG1pbihTdGFiaWxpdHkuQ2hhcmdlKSwNCiAgICAgICAgICAgIHN0YWJpbGl0eV9jaGFyZ2VfbWF4ID0gbWF4KFN0YWJpbGl0eS5DaGFyZ2UpLA0KICAgICAgICAgICAgdG90YWwgPSBuKCkpICU+JQ0KICBhcnJhbmdlKGRlc2Moc3RhYmlsaXR5X2NoYXJnZV9tZWRpYW4pKQ0KDQpwX3N0YWJpbGl0eV9jaGFyZ2Vfd29ya2luZ19pb24gPC0gZ2dwbG90KHN1bW1hcnlfc3RhYmlsaXR5X2NoYXJnZV93b3JraW5nX2lvbiwgYWVzKHggPSB0b3RhbCwgeSA9IHN0YWJpbGl0eV9jaGFyZ2VfbWVkaWFuLCBjb2xvciA9IFdvcmtpbmcuSW9uKSkgKw0KICBnZW9tX3BvaW50KGFlcygNCiAgICB0ZXh0ID0gcGFzdGUoDQogICAgICAiV29ya2luZyBJb246IiwgV29ya2luZy5Jb24sDQogICAgICAiPGJyPk1lZGlhbiA6Iiwgcm91bmQoc3RhYmlsaXR5X2NoYXJnZV9tZWRpYW4sIDIpLA0KICAgICAgIjxicj5NZWFuIDoiLCByb3VuZChzdGFiaWxpdHlfY2hhcmdlX21lYW4sIDIpLA0KICAgICAgIjxicj5NaW4gOiIsIHJvdW5kKHN0YWJpbGl0eV9jaGFyZ2VfbWluLCAyKSwNCiAgICAgICI8YnI+TWF4IDoiLCByb3VuZChzdGFiaWxpdHlfY2hhcmdlX21heCwgMikNCiAgICApDQogICksICBzaXplID0gMykgKw0KICBsYWJzKA0KICAgIHRpdGxlID0gIlN0YWJpbG5vxZvEhyB3IHN0YW5pZSBuYcWCYWRvd2FueW0gYSBnxYLDs3dueSBqb24iLA0KICAgIHggPSAiTGljemJhIG9ic2Vyd2FjamkiLA0KICAgIHkgPSAiV3NrYcW8bmlrIHN0YWJpbG5vxZtjaSB3IHN0YW5pZSBuYcWCYWRvd2FueW0iDQogICkgKw0KICB0aGVtZV9taW5pbWFsKCkNCg0KZ2dwbG90bHkocF9zdGFiaWxpdHlfY2hhcmdlX3dvcmtpbmdfaW9uLCB0b29sdGlwID0gInRleHQiKQ0KDQpzdW1tYXJ5X3N0YWJpbGl0eV9kaXNjaGFyZ2Vfd29ya2luZ19pb24gPC0gZGF0YSAlPiUNCiAgZ3JvdXBfYnkoV29ya2luZy5Jb24pICU+JQ0KICBzdW1tYXJpc2Uoc3RhYmlsaXR5X2Rpc2NoYXJnZV9tZWFuID0gbWVhbihTdGFiaWxpdHkuRGlzY2hhcmdlKSwNCiAgICAgICAgICAgIHN0YWJpbGl0eV9kaXNjaGFyZ2VfbWVkaWFuID0gbWVkaWFuKFN0YWJpbGl0eS5EaXNjaGFyZ2UpLA0KICAgICAgICAgICAgc3RhYmlsaXR5X2Rpc2NoYXJnZV9taW4gPSBtaW4oU3RhYmlsaXR5LkRpc2NoYXJnZSksDQogICAgICAgICAgICBzdGFiaWxpdHlfZGlzY2hhcmdlX21heCA9IG1heChTdGFiaWxpdHkuRGlzY2hhcmdlKSwNCiAgICAgICAgICAgIHRvdGFsID0gbigpKSAlPiUNCiAgYXJyYW5nZShkZXNjKHN0YWJpbGl0eV9kaXNjaGFyZ2VfbWVkaWFuKSkNCg0KcF9zdGFiaWxpdHlfZGlzY2hhcmdlX3dvcmtpbmdfaW9uIDwtIGdncGxvdChzdW1tYXJ5X3N0YWJpbGl0eV9kaXNjaGFyZ2Vfd29ya2luZ19pb24sIGFlcyh4ID0gdG90YWwsIHkgPSBzdGFiaWxpdHlfZGlzY2hhcmdlX21lZGlhbiwgY29sb3IgPSBXb3JraW5nLklvbikpICsNCiAgZ2VvbV9wb2ludCgNCiAgICBhZXMoDQogICAgdGV4dCA9IHBhc3RlKA0KICAgICAgIldvcmtpbmcgSW9uOiIsIFdvcmtpbmcuSW9uLA0KICAgICAgIjxicj5NZWRpYW4gOiIsIHJvdW5kKHN0YWJpbGl0eV9kaXNjaGFyZ2VfbWVkaWFuLCAyKSwNCiAgICAgICI8YnI+TWVhbiA6Iiwgcm91bmQoc3RhYmlsaXR5X2Rpc2NoYXJnZV9tZWFuLCAyKSwNCiAgICAgICI8YnI+TWluIDoiLCByb3VuZChzdGFiaWxpdHlfZGlzY2hhcmdlX21pbiwgMiksDQogICAgICAiPGJyPk1heCA6Iiwgcm91bmQoc3RhYmlsaXR5X2Rpc2NoYXJnZV9tYXgsIDIpDQogICAgKQ0KICApLCBzaXplID0gMykgKw0KICBsYWJzKA0KICAgIHRpdGxlID0gIlN0YWJpbG5vxZvEhyB3IHN0YW5pZSByb3rFgmFkb3dhbnltIGEgZ8WCw7N3bnkgam9uIiwNCiAgICB4ID0gIkxpY3piYSBvYnNlcndhY2ppIiwNCiAgICB5ID0gIldza2HFvG5payBzdGFiaWxub8WbY2kgdyBzdGFuaWUgcm96xYJhZG93YW55bSINCiAgKSArDQogIHRoZW1lX21pbmltYWwoKQ0KDQpnZ3Bsb3RseShwX3N0YWJpbGl0eV9kaXNjaGFyZ2Vfd29ya2luZ19pb24sIHRvb2x0aXAgPSAidGV4dCIpDQpgYGANCg0KKipTdGFiaWxub8WbxIcgdyBzdGFuaWUgbmHFgmFkb3dhbnltOiAqKg0KDQogIC0gV2FydG/Fm2NpIHdza2HFum5pa2Egc3RhYmlsbm/Fm2NpIG1hdGVyaWHFgsOzdyB3IHdpxJlrc3pvxZtjaSBtaWVzemN6xIUgc2nEmSBwb25pxbxlaiAwLDE1IA0KICAtIEpvbnkgd3lrYXp1asSFY2UgbmFqd3nFvHN6xIUgc3RhYmlsbm/Fm8SHIHcgc3RhbmllIG5hxYJhZG93YW55bSB0byBZLCBBbCwgWm4sIENhIGkgTWcgDQogIC0gSm9ueSB3eWthenVqxIVjZSBuYWpuacW8c3rEhSBzdGFiaWxub8WbxIcgdyBzdGFuaWUgbmHFgmFkb3dhbnltIHRvIA0KDQoqKlN0YWJpbG5vxZvEhyB3IHN0YW5pZSByb3rFgmFkb3dhbnltOiAqKg0KDQotIFdhcnRvxZtjaSB3c2thxbpuaWthIHN0YWJpbG5vxZtjaSBtYXRlcmlhxYLDs3cgdyB3acSZa3N6b8WbY2kgbWllc3pjesSFIHNpxJkgcG9uacW8ZWogMCwxMCANCi0gSm9ueSB3eWthenVqxIVjZSBuYWp3ecW8c3rEhSBzdGFiaWxub8WbxIcgdyBzdGFuaWUgbmHFgmFkb3dhbnltIHRvIFksIE1nLCBabiBvcmF6IEFsIA0KDQpTemN6ZWfDs2xuxIUgdXdhZ8SZIHByenljacSFZ2EgbGl0LCBrdMOzcnkgY2hhcmFrdGVyeXp1amUgc2nEmSBuYWp3acSZa3N6xIUgbGljemLEhSBvYnNlcndhY2ppIGkgamVkbm9jemXFm25pZSB6YWptdWplIHBvxZtyZWRuaWUgbWllanNjZSB3IHplc3Rhd2llbml1IHBvZCB3emdsxJlkZW0gd2FydG/Fm2NpIHdza2HFum5pa8OzdyBzdGFiaWxub8WbY2kuDQoNCiMjIyBabWlhbmEgb2JqxJl0b8WbY2kgZGxhIGRhbmVnbyBrcm9rdSBuYXBpxJljaWEgeiBwb2R6aWHFgmVtIG5hIGpvbnkgZ8WCw7N3bmUNCg0KYGBge3Igc3VtbWFyeS1tYXgtZGF0YS12b2x1bWUtd29ya2luZy1pb24sIGZpZy53aWR0aD0xNH0NCg0Kc3VtbWFyeV9tYXhfZGF0YV92b2x1bWVfd29ya2luZ19pb24gPC0gZGF0YSAlPiUNCiAgZ3JvdXBfYnkoV29ya2luZy5Jb24pICU+JQ0KICBzdW1tYXJpc2UobWF4X2RhdGFfdm9sdW1lX21lYW4gPSBtZWFuKE1heC5EZWx0YS5Wb2x1bWUpLA0KICAgICAgICAgICAgbWF4X2RhdGFfdm9sdW1lX21lZGlhbiA9IG1lZGlhbihNYXguRGVsdGEuVm9sdW1lKSwNCiAgICAgICAgICAgIG1heF9kYXRhX3ZvbHVtZV9taW4gPSBtaW4oTWF4LkRlbHRhLlZvbHVtZSksDQogICAgICAgICAgICBtYXhfZGF0YV92b2x1bWVfbWF4ID0gbWF4KE1heC5EZWx0YS5Wb2x1bWUpLA0KICAgICAgICAgICAgdG90YWwgPSBuKCkpICU+JQ0KICBhcnJhbmdlKG1heF9kYXRhX3ZvbHVtZV9tZWFuKQ0KDQprYWJsZShzdW1tYXJ5X21heF9kYXRhX3ZvbHVtZV93b3JraW5nX2lvbikNCg0KcCA8LSBnZ3Bsb3Qoc3VtbWFyeV9tYXhfZGF0YV92b2x1bWVfd29ya2luZ19pb24sIGFlcyh4ID0gdG90YWwsIHkgPSBtYXhfZGF0YV92b2x1bWVfbWVkaWFuLCBjb2xvciA9IFdvcmtpbmcuSW9uKSkgKw0KICBnZW9tX3BvaW50KGFlcygNCiAgICB0ZXh0ID0gcGFzdGUoDQogICAgICAiV29ya2luZyBJb246IiwgV29ya2luZy5Jb24sDQogICAgICAiPGJyPk1lZGlhbiA6Iiwgcm91bmQobWF4X2RhdGFfdm9sdW1lX21lZGlhbiwgMiksDQogICAgICAiPGJyPk1lYW4gOiIsIHJvdW5kKG1heF9kYXRhX3ZvbHVtZV9tZWFuLCAyKSwNCiAgICAgICI8YnI+TWluIDoiLCByb3VuZChtYXhfZGF0YV92b2x1bWVfbWluLCAyKSwNCiAgICAgICI8YnI+TWF4IDoiLCByb3VuZChtYXhfZGF0YV92b2x1bWVfbWF4LCAyKQ0KICAgICkNCiAgKSwgc2l6ZSA9IDMsIGFscGhhID0gMC43KSArDQogIGxhYnMoDQogICAgdGl0bGUgPSAiTWVkaWFuYSB6bWlhbnkgb2JqxJl0b8WbY2kgdyAlIGRsYSBkYW5lZ28ga3Jva3UgbmFwacSZY2lhIGRsYSBqb27Ds3cgZ8WCw7N3bnljaCIsDQogICAgeCA9ICJMaWN6YmEgb2JzZXJ3YWNqaSIsDQogICAgeSA9ICJNZWRpYW5hIG1ha3N5bWFsbmVqIHptaWFueSBvYmrEmXRvxZtjaSINCiAgKSArDQogIHRoZW1lX21pbmltYWwoKSArDQogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJib3R0b20iKQ0KDQpnZ3Bsb3RseShwLCB0b29sdGlwID0gInRleHQiKQ0KYGBgDQoNCk5ham5pxbxzesSFIHptaWFuxIUgbmFwacSZY2lhIGNoYXJha3Rlcnl6dWplIHNpxJkgbGl0IChMaSksIGEgbmFqd3nFvHN6xIUgaXRyIChZKS4NCg0KDQojIyMgUG9qZW1ub8WbxIcgaSBnxJlzdG/Fm8SHIGdyYXdpbWV0cnljem5hDQoNCioqR8SZc3RvxZvEhyBHcmF3aW1ldHJ5Y3puYSoqDQoNCi0gV3NrYXp1amUgaWxlIGVuZXJnaWkgZG9zdMSZcG5laiBqZXN0IHcgYmF0ZXJpaSB3IG9kbmllc2llbml1IGRvIGplaiBtYXN5IChXaC9rZykuDQotIEfEmXN0b8WbxIcgZ3Jhd2ltZXRyeWN6bmEgaW5mb3JtdWplLCBqYWsgZWZla3R5d25pZSBiYXRlcmlhIG1hZ2F6eW51amUgZW5lcmdpxJkgdyBzdG9zdW5rdSBkbyBzd29qZWogd2FnaS4gSmVzdCBrbHVjem93YSBkbGEgYXBsaWthY2ppLCBnZHppZSB3YcW8bmEgamVzdCB6YXLDs3dubyBwb2plbW5vxZvEhyBlbmVyZ2V0eWN6bmEsIGphayBpIGxla2tvxZvEhywgbnAuIHcgc2Ftb2Nob2RhY2ggZWxla3RyeWN6bnljaCBjenkgZHJvbmFjaC4NCg0KYGBge3Igc3VtbWFyeS1ncmF2aW1ldHJpYy1lbmVyZ3ktd29ya2luZy1pb24sIGZpZy53aWR0aD0xNH0NCg0Kc3VtbWFyeV9ncmF2aW1ldHJpY19lbmVyZ3lfd29ya2luZ19pb24gPC0gZGF0YSAlPiUNCiAgZ3JvdXBfYnkoV29ya2luZy5Jb24pICU+JQ0KICBzdW1tYXJpc2UoZ3JhdmltZXRyaWNfZW5lcmd5X21lYW4gPSBtZWFuKEdyYXZpbWV0cmljLkVuZXJneSksDQogICAgICAgICAgICBncmF2aW1ldHJpY19lbmVyZ3lfbWVkaWFuID0gbWVkaWFuKEdyYXZpbWV0cmljLkVuZXJneSksLA0KICAgICAgICAgICAgZ3JhdmltZXRyaWNfZW5lcmd5X21pbiA9IG1pbihHcmF2aW1ldHJpYy5FbmVyZ3kpLA0KICAgICAgICAgICAgZ3JhdmltZXRyaWNfZW5lcmd5X21heCA9IG1heChHcmF2aW1ldHJpYy5FbmVyZ3kpLA0KICAgICAgICAgICAgdG90YWwgPSBuKCkpICU+JQ0KICBhcnJhbmdlKGRlc2MoZ3JhdmltZXRyaWNfZW5lcmd5X21lZGlhbikpDQoNCmthYmxlKHN1bW1hcnlfZ3JhdmltZXRyaWNfZW5lcmd5X3dvcmtpbmdfaW9uKQ0KDQpwIDwtIGdncGxvdChzdW1tYXJ5X2dyYXZpbWV0cmljX2VuZXJneV93b3JraW5nX2lvbiwgYWVzKHggPSB0b3RhbCwgeSA9IGdyYXZpbWV0cmljX2VuZXJneV9tZWRpYW4sIGNvbG9yID0gV29ya2luZy5Jb24pKSArDQogIGdlb21fcG9pbnQoYWVzKA0KICAgIHRleHQgPSBwYXN0ZSgNCiAgICAgICJXb3JraW5nIElvbjoiLCBXb3JraW5nLklvbiwNCiAgICAgICI8YnI+TWVkaWFuIDoiLCByb3VuZChncmF2aW1ldHJpY19lbmVyZ3lfbWVkaWFuLCAyKSwNCiAgICAgICI8YnI+TWVhbiA6Iiwgcm91bmQoZ3JhdmltZXRyaWNfZW5lcmd5X21lYW4sIDIpLA0KICAgICAgIjxicj5NaW4gOiIsIHJvdW5kKGdyYXZpbWV0cmljX2VuZXJneV9taW4sIDIpLA0KICAgICAgIjxicj5NYXggOiIsIHJvdW5kKGdyYXZpbWV0cmljX2VuZXJneV9tYXgsIDIpDQogICAgKQ0KICApLCBzaXplID0gMywgYWxwaGEgPSAwLjcpICsNCiAgbGFicygNCiAgICB0aXRsZSA9ICJNZWRpYW5hIGVuZXJnaWkgZ3Jhd2ltZXRyeWN6bmVqIGRsYSBqb27Ds3cgZ8WCw7N3bnljaCIsDQogICAgeCA9ICJMaWN6YmEgb2JzZXJ3YWNqaSIsDQogICAgeSA9ICJNZWRpYW5hIGVuZXJnaWkgZ3Jhd2ltZXRyeWN6bmVqIg0KICApICsNCiAgdGhlbWVfbWluaW1hbCgpICsNCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gImJvdHRvbSIpDQoNCmdncGxvdGx5KHAsIHRvb2x0aXAgPSAidGV4dCIpDQoNCg0KYGBgDQoNCi0gTmFqd2nEmWtzesSFIGfEmXN0b8WbY2nEhSBncmF3aW1ldHJ5Y3puxIUgY2hhcmFrdGVyeXp1asSFIHNpxJkgbWF0ZXJpYcWCeSBDYSwgTGksIFksIE5hLCBNZw0KLSBOYWptbmllanN6xIUgZ8SZc3RvxZtjacSFIGdyYXdpbWV0cnljem7EhSBjaGFyYWt0ZXJ5enVqxIUgc2nEmSBtYXRlcmlhxYJ5IENzLCBabiwgUmINCg0KKipQb2plbW5vxZvEhyBHcmF3aW1ldHJ5Y3puYSoqDQoNCi0gV3NrYXp1amUgaWxlIGVuZXJnaWkgZWxla3RyeWN6bmVqIGJhdGVyaWEgbW/FvGUgcHJ6ZWNob3dhxIcgdyBwcnplbGljemVuaXUgbmEgamVkbm9zdGvEmSBtYXN5IChtQWgvZykuDQotIEltIHd5xbxzemEgcG9qZW1ub8WbxIcgZ3Jhd2ltZXRyeWN6bmEsIHR5bSB3acSZY2VqIGVuZXJnaWkgYmF0ZXJpYSBtb8W8ZSBwcnplY2hvd3l3YcSHIHByenkgdGVqIHNhbWVqIG1hc2llLiBKZXN0IHRvIGlzdG90bmUgZGxhIHVyesSFZHplxYQgcHJ6ZW5vxZtueWNoLCBnZHppZSB6YWxlxbx5IG5hbSBuYSBtYWtzeW1hbGl6YWNqaSBlbmVyZ2lpIHByenkgbmlld2llbGtpZWogbWFzaWUuDQoNCmBgYHtyIHN1bW1hcnktZ3JhdmltZXRyaWMtY2FwYWNpdHktd29ya2luZy1pb24sIGZpZy53aWR0aD0xNH0NCnN1bW1hcnlfZ3JhdmltZXRyaWNfY2FwYWNpdHlfd29ya2luZ19pb24gPC0gZGF0YSAlPiUNCiAgZ3JvdXBfYnkoV29ya2luZy5Jb24pICU+JQ0KICBzdW1tYXJpc2UoZ3JhdmltZXRyaWNfY2FwYWNpdHlfbWVhbiA9IG1lYW4oR3JhdmltZXRyaWMuQ2FwYWNpdHkpLA0KICAgICAgICAgICAgZ3JhdmltZXRyaWNfY2FwYWNpdHlfbWVkaWFuID0gbWVkaWFuKEdyYXZpbWV0cmljLkNhcGFjaXR5KSwNCiAgICAgICAgICAgIGdyYXZpbWV0cmljX2NhcGFjaXR5X21pbiA9IG1pbihHcmF2aW1ldHJpYy5DYXBhY2l0eSksDQogICAgICAgICAgICBncmF2aW1ldHJpY19jYXBhY2l0eV9tYXggPSBtYXgoR3JhdmltZXRyaWMuQ2FwYWNpdHkpLA0KICAgICAgICAgICAgdG90YWwgPSBuKCkpICU+JQ0KICBhcnJhbmdlKGRlc2MoZ3JhdmltZXRyaWNfY2FwYWNpdHlfbWVkaWFuKSkNCg0KcHJldHR5VGFibGUoc3VtbWFyeV9ncmF2aW1ldHJpY19jYXBhY2l0eV93b3JraW5nX2lvbikNCg0KcCA8LSBnZ3Bsb3Qoc3VtbWFyeV9ncmF2aW1ldHJpY19jYXBhY2l0eV93b3JraW5nX2lvbiwgYWVzKHggPSB0b3RhbCwgeSA9IGdyYXZpbWV0cmljX2NhcGFjaXR5X21lZGlhbiwgY29sb3IgPSBXb3JraW5nLklvbikpICsNCiAgZ2VvbV9wb2ludChhZXMoDQogICAgdGV4dCA9IHBhc3RlKA0KICAgICAgIldvcmtpbmcgSW9uOiIsIFdvcmtpbmcuSW9uLA0KICAgICAgIjxicj5NZWRpYW4gOiIsIHJvdW5kKGdyYXZpbWV0cmljX2NhcGFjaXR5X21lZGlhbiwgMiksDQogICAgICAiPGJyPk1lYW4gOiIsIHJvdW5kKGdyYXZpbWV0cmljX2NhcGFjaXR5X21lYW4sIDIpLA0KICAgICAgIjxicj5NaW4gOiIsIHJvdW5kKGdyYXZpbWV0cmljX2NhcGFjaXR5X21pbiwgMiksDQogICAgICAiPGJyPk1heCA6Iiwgcm91bmQoZ3JhdmltZXRyaWNfY2FwYWNpdHlfbWF4LCAyKQ0KICAgICkNCiAgKSwgc2l6ZSA9IDMsIGFscGhhID0gMC43KSArDQogIGxhYnMoDQogICAgdGl0bGUgPSAiTWVkaWFuYSBwb2plbW5vxZtjaSBncmF3aW1ldHJ5Y3puZWogZGxhIGfFgsOzd255Y2ggam9uw7N3IiwNCiAgICB4ID0gIkxpY3piYSBvYnNlcndhY2ppIiwNCiAgICB5ID0gIk1lZGlhbmEgcG9qZW1ub8WbY2kgZ3Jhd2ltZXRyeWN6bmVqIg0KICApICsNCiAgdGhlbWVfbWluaW1hbCgpICsNCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gImJvdHRvbSIpDQoNCmdncGxvdGx5KHAsIHRvb2x0aXAgPSAidGV4dCIpDQoNCmBgYA0KDQotIE5handpxJlrc3rEhSBwb2plbW5vxZtjacSFIGdyYXdpbWV0cnljem7EhSBjaGFyYWt0ZXJ5enVqxIUgc2nEmSBtYXRlcmlhxYJ5IEFsLCBZLCBNZywgQ2EsIFpuDQotIE5ham1uaWVqc3rEhSBwb2plbW5vxZtjacSFIGdyYXdpbWV0cnljem7EhSBjaGFyYWt0ZXJ5enVqxIUgc2nEmSBtYXRlcmlhxYJ5IENzLCBSYg0KDQpaYXLDs3dubyBydWJpZCAoUmIpIGphayBpIENleiAoQ3MpLCBrdMOzcmUgd3lwYWRhasSFIG5hamdvcnplaiBwb2Qgd3pnbMSZZGVtIGVuZXJnaWkgaSBnZXN0b8WbY2kgZ3Jhd2ltZXRyeWN6bmVqIHPEhSBuYWpyemFkemllaiB3eWtvcnp5c3R5d2FueW1pIGpvbmFtaSBnxYLDs3dueW1pLg0KDQotLS0tLS0tLS0tLQ0KDQpQb25pxbxzenkgd3lrcmVzIHByemVkc3Rhd2lhIHphbGXFvG5vxZvEhyBtacSZZHp5IGxpY3pixIUgb2JzZXJ3YWNqaSBkbGEgbmFqY3rEmcWbY2llaiB3eXN0xJlwdWrEhWN5Y2ggV3pvcsOzdyBjaGVtaWN6bnljaCBtYXRlcmlhxYLDs3cgYmF0ZXJpaSB3IHN0YW5pZSBuYcWCYWRvd2FueW0gYSBtZWRpYW7EhSBzdGFiaWxub8WbY2kgdyBzdGFuaWUgbmHFgmFkb3dhbnltLiBEbGEga2HFvGRlZ28gd3pvcnUgb2JsaWN6b25vIG1pYXJ5IHN0YXR5Y3puZSwga3TDs3JlIHd5xZt3aWV0bGFqxIUgc2nEmSBwbyBuYWplY2hhbml1IG5hIHB1bmt0Lg0KDQpgYGB7ciBjaGFyZ2Utc3RhYmlsaXR5LWZvcm1hdWxhLWNoYXJnZS1zdW1tYXJ5LCBmaWcud2lkdGg9MTR9DQoNCmZvcm11bGFfY2hhcmdlX3N1bW1hcnkgPC0gZGF0YSAlPiUNCiAgZ3JvdXBfYnkoRm9ybXVsYS5DaGFyZ2UpICU+JQ0KICBzdW1tYXJpc2UodG90YWwgPSBuKCkpICU+JQ0KICBhcnJhbmdlKGRlc2ModG90YWwpKQ0KDQpwZXJjZW50aWxlXzk5IDwtIHF1YW50aWxlKHNlbGVjdChmb3JtdWxhX2NoYXJnZV9zdW1tYXJ5LCB0b3RhbCksIHByb2JzID0gMC45OSwgbmEucm0gPSBUUlVFKQ0KZm9ybXVsYV9jaGFyZ2VfdmFsdWVzXzk5X3BlcmNlbnRpbGUgPC0gZm9ybXVsYV9jaGFyZ2Vfc3VtbWFyeSAlPiUNCiAgZmlsdGVyKHRvdGFsID49IHBlcmNlbnRpbGVfOTkpDQoNCnN1bW1hcnlfZGF0YSA8LSBkYXRhICU+JQ0KICBmaWx0ZXIoRm9ybXVsYS5DaGFyZ2UgJWluJSBmb3JtdWxhX2NoYXJnZV92YWx1ZXNfOTlfcGVyY2VudGlsZSRGb3JtdWxhLkNoYXJnZSkgJT4lDQogIGdyb3VwX2J5KEZvcm11bGEuQ2hhcmdlKSAlPiUNCiAgc3VtbWFyaXNlKHRvdGFsID0gbigpLA0KICAgIHN0YWJpbGl0eV9jaGFyZ2VfbWVhbiA9IG1lYW4oU3RhYmlsaXR5LkNoYXJnZSksDQogICAgICAgICAgICBzdGFiaWxpdHlfY2hhcmdlX21lZGlhbiA9IG1lZGlhbihTdGFiaWxpdHkuQ2hhcmdlKSwNCiAgICAgICAgICAgIHN0YWJpbGl0eV9jaGFyZ2VfbWluID0gbWluKFN0YWJpbGl0eS5DaGFyZ2UpLA0KICAgICAgICAgICAgc3RhYmlsaXR5X2NoYXJnZV9tYXggPSBtYXgoU3RhYmlsaXR5LkNoYXJnZSkpICU+JQ0KICBhcnJhbmdlKGRlc2ModG90YWwpKQ0KDQpwIDwtIGdncGxvdChzdW1tYXJ5X2RhdGEsIGFlcyh4ID0gdG90YWwsIHkgPSBzdGFiaWxpdHlfY2hhcmdlX21lZGlhbikpICsNCiAgZ2VvbV9wb2ludChhZXMoDQogICAgdGV4dCA9IHBhc3RlKA0KICAgICAgIkZvcm11bGEgY2hhcmdlOiIsIEZvcm11bGEuQ2hhcmdlLA0KICAgICAgIjxicj5TdGFiaWxpdHkgY2hhcmdlIG1lZGlhbjoiLCByb3VuZChzdGFiaWxpdHlfY2hhcmdlX21lZGlhbiwgNCksDQogICAgICAiPGJyPlN0YWJpbGl0eSBjaGFyZ2UgbWVhbjoiLCByb3VuZChzdGFiaWxpdHlfY2hhcmdlX21lYW4sIDQpLA0KICAgICAgIjxicj5NaW4gU3RhYmlsaXR5OiIsIHJvdW5kKHN0YWJpbGl0eV9jaGFyZ2VfbWluLCA0KSwNCiAgICAgICI8YnI+TWF4IFN0YWJpbGl0eToiLCByb3VuZChzdGFiaWxpdHlfY2hhcmdlX21heCwgNCkNCiAgICApLA0KICAgIHNpemUgPSB0b3RhbCwgY29sb3IgPSBzdGFiaWxpdHlfY2hhcmdlX21lZGlhbg0KICApLCBhbHBoYSA9IDAuNykgKw0KICBzY2FsZV9jb2xvcl9ncmFkaWVudChsb3cgPSAiYmx1ZSIsIGhpZ2ggPSAicmVkIikgKw0KICBzY2FsZV9zaXplX2NvbnRpbnVvdXMocmFuZ2UgPSBjKDIsIDEwKSkgKw0KICBsYWJzKA0KICAgIHRpdGxlID0gIk1lZGlhbmEgc3RhYmlsbm/Fm2NpIHcgc3RhbmllIG5hxYJhZG93YW55bSA8YnI+ZGxhIG5hamN6xJlzdHN6eWNoIHd6b3LDs3cgY2hlbWljem55Y2ggbWF0ZXJpYcWCw7N3IGJhdGVyaWkiLA0KICAgIHggPSAiTGljemJhIG9ic2Vyd2FjamkiLA0KICAgIHkgPSAiTWVkaWFuYSBzdGFiaWxub8WbY2kgdyBzdGFuaWUgbmHFgmFkb3dhbnltIg0KICApICsNCiAgdGhlbWVfbWluaW1hbCgpICsNCiAgdGhlbWUoDQogICAgbGVnZW5kLnBvc2l0aW9uID0gImJvdHRvbSIsDQogICAgcGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChoanVzdCA9IDAuNSkNCiAgKQ0KDQpnZ3Bsb3RseShwLCB0b29sdGlwID0gInRleHQiKQ0KDQpgYGANCg0KDQojIFByZWR5a2NqYSBjZWNoIGkgd8WCYcWbY2l3b8WbY2kgYmF0ZXJpaQ0KDQojIyBQcmVkeWtjamEgcG9qZW1ub8WbY2kgZ3Jhd2ltZXRyeWN6bmVqIG1ldG9kxIUgcmVncmVzamkNCg0KSmFrbyB6bWllbm7EhSBjZWx1IG9icmFubyBwb2plbW5vxZvEhyBncmF3aW1ldHJ5Y3puxIUuIA0KDQovL1RPRE8gZGVsZXRlDQpgYGB7cn0NCmxpYnJhcnkoImNhcmV0IikNCnNldC5zZWVkKDIzKQ0KDQpkYXRhc2V0X3RvX3RyYWluICA8LSBzZWxlY3QoZGF0YSwgLShCYXR0ZXJ5LklEOkZvcm11bGEuRGlzY2hhcmdlKSkNCg0KaWYgKGlzLmZhY3RvcihkYXRhJFN0YWJpbGl0eS5DaGFyZ2UpKSB7DQogICAgIyBPcHRpb25hbDogSWYgaXQgc2hvdWxkIGJlIG51bWVyaWMgaW4gdGhlIGZpcnN0IHBsYWNlDQogICAgZGF0YSRTdGFiaWxpdHkuQ2hhcmdlIDwtIGFzLm51bWVyaWMoYXMuY2hhcmFjdGVyKGRhdGEkU3RhYmlsaXR5LkNoYXJnZSkpDQp9DQoNCg0KaGVhZChkYXRhc2V0X3RvX3RyYWluKQ0KDQppblRyYWluaW5nIDwtIA0KICAgIGNyZWF0ZURhdGFQYXJ0aXRpb24oDQogICAgICAgIHkgPSBkYXRhJFN0YWJpbGl0eS5DaGFyZ2UsDQogICAgICAgIHAgPSAuNzUsDQogICAgICAgIGxpc3QgPSBGQUxTRSkNCg0KdHJhaW5pbmcgPC0gZGF0YXNldF90b190cmFpblsgaW5UcmFpbmluZyxdDQp0ZXN0aW5nICA8LSBkYXRhc2V0X3RvX3RyYWluWy1pblRyYWluaW5nLF0NCg0KY3RybCA8LSB0cmFpbkNvbnRyb2woDQogICAgIyBwb3d0w7Nyem9uYSBvY2VuYSBrcnp5xbxvd2ENCiAgICBtZXRob2QgPSAicmVwZWF0ZWRjdiIsDQogICAgIyBsaWN6YmEgcG9kemlhxYLDs3cNCiAgICBudW1iZXIgPSAyLA0KICAgICMgbGljemJhIHBvd3TDs3J6ZcWEDQogICAgcmVwZWF0cyA9IDUpDQoNCmZpdCA8LSB0cmFpbihTdGFiaWxpdHkuQ2hhcmdlIH4gLiwNCiAgICAgICAgICAgICBkYXRhID0gdHJhaW5pbmcsDQogICAgICAgICAgICAgbWV0aG9kID0gInJmIiwNCiAgICAgICAgICAgICB0ckNvbnRyb2wgPSBjdHJsLA0KICAgICAgICAgICAgICMgUGFyYW10ZXIgZGxhIGFsZ29yeXRtdSB1Y3rEhWNlZ28NCiAgICAgICAgICAgICBudHJlZSA9IDEwKQ0KDQpmaXQNCmBgYA0KYGBge3J9DQppZHggPC0gY3JlYXRlRGF0YVBhcnRpdGlvbihkYXRhJEdyYXZpbWV0cmljLkNhcGFjaXR5LHA9MC43LCBsaXN0PUYpDQpkMSA8LSBkYXRhLmZyYW1lKGdyYXZpbWV0cmljQ2FwYWNpdHk9ZGF0YVtpZHgsXSRHcmF2aW1ldHJpYy5DYXBhY2l0eSkNCmQyIDwtIGRhdGEuZnJhbWUoZ3JhdmltZXRyaWNDYXBhY2l0eT1kYXRhWy1pZHgsXSRHcmF2aW1ldHJpYy5DYXBhY2l0eSkNCg0KZ2dwbG90KG1hcHBpbmc9YWVzKGFscGhhPTAuNCkpICsgDQogZ2VvbV9kZW5zaXR5KGFlcyhncmF2aW1ldHJpY0NhcGFjaXR5LCBmaWxsPSJyZWQiKSwgZDEpICsgDQogZ2VvbV9kZW5zaXR5KGFlcyhncmF2aW1ldHJpY0NhcGFjaXR5LCBmaWxsPSJibHVlIiksIGQyKSArIA0KIHRoZW1lX21pbmltYWwoKQ0KYGBgDQoNClByenlnb3Rvd2FuaWUgemJpb3J1IGRvIHRyZW5vd2FuaWENCg0KWmUgemJpb3J1IHVzdW5pxJl0byBhdHJ5YnV0eTogXA0KLSBJRCAtIG5pZSBtYSB3cMWCeXd1IG5hIHptaWVubsSFIGNlbHUNCi0gQmF0dGVyeS5Gb3JtdWxhIC0gYmFyZHpvIGR1xbxvIHVuaWthbG55Y2ggd2FydG/Fm2NpLCB3acSZY2VqIG5pxbwgcG/Fgm93YSByb3ptaWFydSB6YmlvcnUsIGlzdG5pZWplIHJ5enlrbyBwcnpldWN6ZW5pYSBpIG5hZG1pZXJuZWogc2VnbWVudGFjamkNCi0gRm9ybXVsYS5DaGFyZ2UgLSBwb2RvYm5pZSBqYWsgIEJhdHRlcnkuRm9ybXVsYSAtIGJhcmR6byBkdcW8byB1bmlrYWxueWNoIHdhcnRvxZtjaQ0KLSBGb3JtdWxhLkRpc2NoYXJnZSAtIHBvZG9ibmllIGphayB3ecW8ZWoNCg0KU2thbG93YW5pZSBpIG5vcm1hbGl6YWNqYSB6bWllbm55Y2gNCg0KYGBge3J9DQojZGF0YXNldF90cmFpbl9zZWxlY3RlZF9hdHRyICA8LSBzZWxlY3QoZGF0YSwgLWMoQmF0dGVyeS5JRCwgQmF0dGVyeS5Gb3JtdWxhLCBGb3JtdWxhLkNoYXJnZSwgRm9ybXVsYS5EaXNjaGFyZ2UpKQ0KZGF0YXNldF9udW1lcmljYWxfYXR0cnMgPC0gc2VsZWN0KGRhdGEsIG51bWVyaWNhbF9hdHRycykNCnByZVByb2MgPC0gcHJlUHJvY2VzcyhkYXRhc2V0X251bWVyaWNhbF9hdHRycywgbWV0aG9kID0gYygiY2VudGVyIiwgInNjYWxlIikpDQpkYXRhX3NjYWxlZCA8LSBwcmVkaWN0KHByZVByb2MsIG5ld2RhdGEgPSBkYXRhc2V0X251bWVyaWNhbF9hdHRycykNCmRhdGFfc2NhbGVkJFdvcmtpbmcuSW9uIDwtIGRhdGEkV29ya2luZy5Jb24NCmRhdGFfc2NhbGVkDQoNCmRhdGFfc2NhbGVkIDwtIGRhdGFzZXRfbnVtZXJpY2FsX2F0dHJzDQoNCnNraW0oZGF0YV9zY2FsZWQpDQoNCmR1bW1pZXMgPC0gZHVtbXlWYXJzKCJ+IC4iLCBkYXRhID0gZGF0YV9zY2FsZWQpDQpkYXRhX3RyYW5zZm9ybWVkIDwtIGRhdGEuZnJhbWUocHJlZGljdChkdW1taWVzLCBuZXdkYXRhID0gZGF0YV9zY2FsZWQpKQ0KDQpoZWFkKGRhdGFfdHJhbnNmb3JtZWQpDQoNCmFub3ZhX3Jlc3VsdCA8LSBhb3YoR3JhdmltZXRyaWMuQ2FwYWNpdHkgfiBCYXR0ZXJ5LkZvcm11bGEsIGRhdGEgPSBkYXRhKQ0Kc3VtbWFyeShhbm92YV9yZXN1bHQpDQpgYGANCg0KVXN1bmnEmWNpZSB6bWllbm55Y2ggc2tvcmVsb3dhbnljaA0KDQpgYGB7cn0NCiMgVXN1bmnEmWNpZSB6bWllbm55Y2ggc2tvcmVsb3dhbnljaA0KY29yX21hdHJpeCA8LSBjb3IoZGF0YV90cmFuc2Zvcm1lZCkNCmhpZ2hfY29yciA8LSBmaW5kQ29ycmVsYXRpb24oY29yX21hdHJpeCwgY3V0b2ZmID0gMC44KQ0KZGF0YV9yZWR1Y2VkIDwtIGRhdGFfdHJhbnNmb3JtZWRbLCAtaGlnaF9jb3JyXQ0KY29sbmFtZXMoZGF0YV9yZWR1Y2VkW2hpZ2hfY29ycl0pDQoNCnRhcmdldEF0dHIgPC0gIlZvbHVtZXRyaWMuRW5lcmd5Ig0KdGFyZ2V0IDwtIGRhdGFfcmVkdWNlZCRWb2x1bWV0cmljLkVuZXJneQ0KcHJlZGljdG9ycyA8LSBkYXRhX3JlZHVjZWRbLCAtd2hpY2gobmFtZXMoZGF0YV9yZWR1Y2VkKSA9PSB0YXJnZXRBdHRyKV0NCg0KI2RhdGFfcmVkdWNlZCA8LSBkYXRhc2V0X251bWVyaWNhbF9hdHRycw0KI2RhdGFfcmVkdWNlZA0KDQojIFBvZHppYcWCIGRhbnljaA0Kc2V0LnNlZWQoMTIzKQ0KdHJhaW5JbmRleCA8LSBjcmVhdGVEYXRhUGFydGl0aW9uKHRhcmdldCwgcCA9IDAuNywgbGlzdCA9IEZBTFNFKQ0KdHJhaW5EYXRhIDwtIGRhdGFfcmVkdWNlZFt0cmFpbkluZGV4LCBdDQp0ZXN0RGF0YSA8LSBkYXRhX3JlZHVjZWRbLXRyYWluSW5kZXgsIF0NCg0KZ2dwbG90KCkgKw0KICBnZW9tX2RlbnNpdHkoZGF0YSA9IHRyYWluRGF0YSwgYWVzKHggPSAhIXN5bSh0YXJnZXRBdHRyKSwgZmlsbCA9ICJUcmFpbiIpLCBhbHBoYSA9IDAuMykgKw0KICBnZW9tX2RlbnNpdHkoZGF0YSA9IHRlc3REYXRhLCBhZXMoeCA9ICEhc3ltKHRhcmdldEF0dHIpLCBmaWxsID0gIlRlc3QiKSwgYWxwaGEgPSAwLjMpICsNCiAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzID0gYygiVHJhaW4iID0gInJlZCIsICJUZXN0IiA9ICJibHVlIikpICsNCiAgdGhlbWVfbWluaW1hbCgpICsNCiAgbGFicyh0aXRsZSA9ICJQb3LDs3duYW5pZSByb3prxYJhZHUgem1pZW5uZWogY2VsdSB3IHpiaW9yYWNoIHRyZW5pbmdvd3ltIGkgdGVzdG93eW0iLA0KICAgICAgIHggPSB0YXJnZXRBdHRyLA0KICAgICAgIHkgPSAiR8SZc3RvxZvEhyIsDQogICAgICAgZmlsbCA9ICJaYmnDs3IiKQ0KDQoNCnRhcmdldEF0dHIgPC0gIlZvbHVtZXRyaWMuRW5lcmd5Ig0KZm9ybXVsYSA8LSBhcy5mb3JtdWxhKHBhc3RlKHRhcmdldEF0dHIsICJ+IC4iKSkNCg0KbW9kZWwgPC0gdHJhaW4oDQogIGZvcm11bGEsIA0KICBkYXRhID0gdHJhaW5EYXRhLCANCiAgbWV0aG9kID0gImxtIiwgDQogIHRyQ29udHJvbCA9IHRyYWluQ29udHJvbChtZXRob2QgPSAiY3YiLCBudW1iZXIgPSAxMCkNCikNCg0Kc3VtbWFyeShtb2RlbCkNCg0KcHJlZGljdGlvbnMgPC0gcHJlZGljdChtb2RlbCwgbmV3ZGF0YSA9IHRlc3REYXRhKQ0KcG9zdFJlc2FtcGxlKHByZWRpY3Rpb25zLCB0ZXN0RGF0YVtbdGFyZ2V0QXR0cl1dKQ0KDQpwbG90KHRlc3REYXRhW1t0YXJnZXRBdHRyXV0sIHByZWRpY3Rpb25zLCANCiAgICAgbWFpbiA9IHBhc3RlKCJQcmVkaWN0ZWQgdnMgQWN0dWFsIiwgdGFyZ2V0QXR0ciksDQogICAgIHhsYWIgPSAiUnplY3p5d2lzdGUiLCB5bGFiID0gIlByemV3aWR5d2FuZSIpDQphYmxpbmUoMCwgMSwgY29sID0gInJlZCIpDQoNCmBgYA0KDQpgYGB7cn0NCmxpYnJhcnkoTWV0cmljcykNCg0KbnVtZXJpY2FsIDwtIHNlbGVjdChkYXRhLCAtYyhCYXR0ZXJ5LklELCBCYXR0ZXJ5LkZvcm11bGEpKQ0KaGlnaF9jb3JfYXR0cmlidXRlcyA8LSBjb3JfbWF0cml4ICU+JSBmaW5kQ29ycmVsYXRpb24oY3V0b2ZmID0gMC44LCBuYW1lcyA9IFRSVUUpDQoNCmRhdGFfcmVkdWNlZCA8LSBzZWxlY3QoZGF0YV90cmFuc2Zvcm1lZCwgLShoaWdoX2Nvcl9hdHRyaWJ1dGVzKSkNCg0KaWR4IDwtIGNyZWF0ZURhdGFQYXJ0aXRpb24oZGF0YV9yZWR1Y2VkJFZvbHVtZXRyaWMuRW5lcmd5LCBwPTAuNywgbGlzdD1GKQ0KDQp0cmFpbl9kYXRhIDwtIGRhdGFfcmVkdWNlZFtpZHgsIF0NCnRlc3RfZGF0YSA8LSBkYXRhX3JlZHVjZWRbLWlkeCwgXQ0KDQpnZ3Bsb3QobWFwcGluZyA9IGFlcyhhbHBoYSA9IDAuNCkpICsgDQogIGdlb21fZGVuc2l0eShhZXMoeCA9IFZvbHVtZXRyaWMuRW5lcmd5LCBmaWxsID0gInJlZCIpLCBkYXRhID0gdHJhaW5fZGF0YSkgKyANCiAgZ2VvbV9kZW5zaXR5KGFlcyh4ID0gVm9sdW1ldHJpYy5FbmVyZ3ksIGZpbGwgPSAiYmx1ZSIpLCBkYXRhID0gdGVzdF9kYXRhKSArIA0KICB0aGVtZV9taW5pbWFsKCkNCg0KDQptb2RlbCA8LSB0cmFpbigNCiAgVm9sdW1ldHJpYy5FbmVyZ3l+LiwgDQogIGRhdGEgPSB0cmFpbl9kYXRhLCANCiAgbWV0aG9kID0gImxtIiwgDQogIHRyQ29udHJvbCA9IHRyYWluQ29udHJvbChtZXRob2QgPSAiY3YiLCBudW1iZXIgPSAxMCkNCikNCg0Kc3VtbWFyeShtb2RlbCkNCg0KcHJlZGljdGlvbnMgPC0gcHJlZGljdChtb2RlbCwgbmV3ZGF0YSA9IHRlc3RfZGF0YSkNCg0KIyBDb21wYXJlIHByZWRpY3RlZCB2cyBhY3R1YWwgdmFsdWVzDQpjb21wYXJpc29uIDwtIGRhdGEuZnJhbWUoQWN0dWFsID0gdGVzdF9kYXRhJFZvbHVtZXRyaWMuRW5lcmd5LCBQcmVkaWN0ZWQgPSBwcmVkaWN0aW9ucykNCg0KDQpwcmludChjb21wYXJpc29uKQ0KcG9zdFJlc2FtcGxlKHByZWRpY3Rpb25zLCB0ZXN0X2RhdGEkVm9sdW1ldHJpYy5FbmVyZ3kpDQoNCnJtc2VfdmFsdWUgPC0gcm1zZSh0ZXN0X2RhdGEkVm9sdW1ldHJpYy5FbmVyZ3ksIHByZWRpY3Rpb25zKQ0KY2F0KCJSTVNFOiIsIHJtc2VfdmFsdWUsICJcbiIpDQoNCmdncGxvdChjb21wYXJpc29uLCBhZXMoeCA9IEFjdHVhbCwgeSA9IFByZWRpY3RlZCkpICsNCiAgZ2VvbV9wb2ludChhbHBoYSA9IDAuNSkgKw0KICBnZW9tX2FibGluZShpbnRlcmNlcHQgPSAwLCBzbG9wZSA9IDEsIGNvbG9yID0gInJlZCIpICsNCiAgbGFicyh0aXRsZSA9ICJBY3R1YWwgdnMgUHJlZGljdGVkIFZhbHVlcyIsDQogICAgICAgeCA9ICJBY3R1YWwgVm9sdW1ldHJpYyBFbmVyZ3kiLA0KICAgICAgIHkgPSAiUHJlZGljdGVkIFZvbHVtZXRyaWMgRW5lcmd5IikgKw0KICB0aGVtZV9taW5pbWFsKCkNCg0KYGBgDQojIyMgUHJlcHJvY2Vzc2luZyBkYW55Y2gNCg0KUHJlcHJvY2Vzc2luZyBkYW55Y2ggb2Jlam11amUgbmFzdMSZcHVqxIVjZSBrcm9raToNCi0gVXN1bmnEmWNpZSBhdHJ5YnV0w7N3LCBrdMOzcmUgbmllIG1hasSFIHdwxYJ5d3UgbmEgem1pZW5uxIUgY2VsdSAgDQoNCmBgYHtyfQ0KYmF0dGVyeV90cmFpbl9kYXRhIDwtIHNlbGVjdChkYXRhLCAtYyhCYXR0ZXJ5LklELCBCYXR0ZXJ5LkZvcm11bGEpKQ0KaGlnaF9jb3JfYXR0cmlidXRlcyA8LSBjb3JfbWF0cml4ICU+JSBmaW5kQ29ycmVsYXRpb24oY3V0b2ZmID0gMC44LCBuYW1lcyA9IFRSVUUpDQpoaWdoX2Nvcl9hdHRyaWJ1dGVzDQpgYGANCg0KLSBVc3VuacSZY2llIHptaWVubnljaCB3eXNva28gc2tvcmVsb3dhbnljaCB6ZSB6bWllbm7EhSBjZWx1LiBBdHJ5YnV0eSwga3TDs3JlIHpvc3RhxYJ5IHVzdW5pxJl0ZSB0byBgciBoaWdoX2Nvcl9hdHRyaWJ1dGVzYC4NCg0KDQpgYGB7cn0NCnRyYWluIDwtIHNlbGVjdChiYXR0ZXJ5X3RyYWluX2RhdGEsIC0oaGlnaF9jb3JfYXR0cmlidXRlcykpDQpgYGANCg0KDQpgYGB7cn0NCg0Kb3V0bGllcl90aHJlc2hvbGQgPC0gMg0KDQpkZXRlY3Rfb3V0bGllcnMgPC0gZnVuY3Rpb24oeCkgew0KICBRMSA8LSBxdWFudGlsZSh4LCAwLjI1LCBuYS5ybSA9IFRSVUUpDQogIFEzIDwtIHF1YW50aWxlKHgsIDAuNzUsIG5hLnJtID0gVFJVRSkNCiAgSVFSIDwtIFEzIC0gUTENCiAgcmV0dXJuKHggPCAoUTEgLSAxLjUgKiBJUVIpIHwgeCA+IChRMyArIDEuNSAqIElRUikpDQp9DQoNCm91dGxpZXJfbWF0cml4IDwtIGFzLmRhdGEuZnJhbWUobGFwcGx5KHRyYWluLCBmdW5jdGlvbihjb2x1bW4pIHsNCiAgaWYgKGlzLm51bWVyaWMoY29sdW1uKSkgew0KICAgIHJldHVybihkZXRlY3Rfb3V0bGllcnMoY29sdW1uKSkNCiAgfSBlbHNlIHsNCiAgICByZXR1cm4ocmVwKEZBTFNFLCBsZW5ndGgoY29sdW1uKSkpDQogIH0NCn0pKQ0KDQpvdXRsaWVyX2NvdW50IDwtIHJvd1N1bXMob3V0bGllcl9tYXRyaXgpDQpucm93KHRyYWluW291dGxpZXJfY291bnQgPj0gb3V0bGllcl90aHJlc2hvbGQsXSkNCg0KZGF0YV9jbGVhbmVkIDwtIHRyYWluW291dGxpZXJfY291bnQgPCBvdXRsaWVyX3RocmVzaG9sZCwgXQ0Kc2tpbShkYXRhX2NsZWFuZWQpDQpgYGANCi0gV3ljenlzemN6ZW5pZSB3YXJ0b8WbY2kgb2RzdGFqxIVjeWNoLiBEbyBpZGVudHlmaWthY2ppIG91dGxpZXLDs3cgd3lrb3J6eXN0YW5vIG1ldG9kxJkgSVFSLiBVc3VuacSZdG8gcmVrb3JkeSwga3TDs3JlIHBvc2lhZGHFgnkgd2FydG/Fm2NpIG9kc3RhasSFY2UgbmEgY28gbmFqbW5pZWogYHIgb3V0bGllcl90aHJlc2hvbGRgIGF0cnlidXRhY2guDQogWm9zdGHFgm8gdXN1bmnEmXR5Y2ggYHIgbnJvdyh0cmFpbltvdXRsaWVyX2NvdW50ID49IG91dGxpZXJfdGhyZXNob2xkLF0pYCByZWtvcmTDs3cuDQoNCi0gTm9ybWFsaXphY2phIGRhbnljaA0KDQpgYGB7cn0NCmRhdGFfc2NhbGVkIDwtIGFzLmRhdGEuZnJhbWUobGFwcGx5KHRyYWluLCBmdW5jdGlvbihjb2wpIHsNCiAgaWYgKGlzLm51bWVyaWMoY29sKSkgew0KICAgIHJlc2NhbGUoY29sKQ0KICB9IGVsc2Ugew0KICAgIGNvbCAgDQogIH0NCn0pKQ0KDQpza2ltKGRhdGFfc2NhbGVkKQ0KYGBgDQoNCg0KDQpgYGB7cn0NCg0KaWR4IDwtIGNyZWF0ZURhdGFQYXJ0aXRpb24oZGF0YV9zY2FsZWQkVm9sdW1ldHJpYy5FbmVyZ3ksIHA9MC43LCBsaXN0PUYpDQoNCnRyYWluX2RhdGEgPC0gZGF0YV9zY2FsZWRbaWR4LCBdDQp0ZXN0X2RhdGEgPC0gZGF0YV9zY2FsZWRbLWlkeCwgXQ0KDQpjdHJsIDwtIHRyYWluQ29udHJvbChtZXRob2QgPSAiY3YiLCBudW1iZXIgPSAxMCkNCg0KZ2dwbG90KG1hcHBpbmcgPSBhZXMoYWxwaGEgPSAwLjQpKSArIA0KICBnZW9tX2RlbnNpdHkoYWVzKHggPSBWb2x1bWV0cmljLkVuZXJneSwgZmlsbCA9ICJyZWQiKSwgZGF0YSA9IHRyYWluX2RhdGEpICsgDQogIGdlb21fZGVuc2l0eShhZXMoeCA9IFZvbHVtZXRyaWMuRW5lcmd5LCBmaWxsID0gImJsdWUiKSwgZGF0YSA9IHRlc3RfZGF0YSkgKyANCiAgdGhlbWVfbWluaW1hbCgpDQoNCmBgYA0KDQpgYGB7cn0NCm1vZGVsIDwtIHRyYWluKA0KICBWb2x1bWV0cmljLkVuZXJneX4uLCANCiAgZGF0YSA9IHRyYWluX2RhdGEsIA0KICBtZXRob2QgPSAibG0iLCANCiAgdHJDb250cm9sID0gY3RybA0KKQ0KYGBgDQoNCmBgYHtyfQ0Kc3VtbWFyeShtb2RlbCkNCmBgYA0KDQoNCg0KDQo=